janito 3.5.0__py3-none-any.whl → 3.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- janito/plugins/core/system/tools/run_bash_command.py +23 -2
- janito/plugins/core/system/tools/run_powershell_command.py +16 -0
- janito/plugins/tools/python_code_run.py +20 -4
- janito/plugins/tools/python_command_run.py +18 -2
- janito/plugins/tools/python_file_run.py +18 -2
- {janito-3.5.0.dist-info → janito-3.5.1.dist-info}/METADATA +1 -1
- {janito-3.5.0.dist-info → janito-3.5.1.dist-info}/RECORD +11 -14
- janito/plugins/dev/pythondev/tools/python_code_run.py +0 -172
- janito/plugins/dev/pythondev/tools/python_command_run.py +0 -171
- janito/plugins/dev/pythondev/tools/python_file_run.py +0 -172
- {janito-3.5.0.dist-info → janito-3.5.1.dist-info}/WHEEL +0 -0
- {janito-3.5.0.dist-info → janito-3.5.1.dist-info}/entry_points.txt +0 -0
- {janito-3.5.0.dist-info → janito-3.5.1.dist-info}/licenses/LICENSE +0 -0
- {janito-3.5.0.dist-info → janito-3.5.1.dist-info}/top_level.txt +0 -0
@@ -30,7 +30,11 @@ class RunBashCommandTool(ToolBase):
|
|
30
30
|
tool_name = "run_bash_command"
|
31
31
|
|
32
32
|
def _stream_output(self, stream, file_obj, report_func, count_func, counter):
|
33
|
+
import threading
|
33
34
|
for line in stream:
|
35
|
+
# Check for cancellation
|
36
|
+
if hasattr(self, '_cancel_event') and self._cancel_event.is_set():
|
37
|
+
break
|
34
38
|
file_obj.write(line)
|
35
39
|
file_obj.flush()
|
36
40
|
report_func(line.rstrip("\r\n"), ReportAction.EXECUTE)
|
@@ -87,6 +91,11 @@ class RunBashCommandTool(ToolBase):
|
|
87
91
|
bufsize=1,
|
88
92
|
env=env,
|
89
93
|
)
|
94
|
+
# Set up cancellation event
|
95
|
+
from janito.llm.cancellation_manager import get_cancellation_manager
|
96
|
+
cancel_manager = get_cancellation_manager()
|
97
|
+
self._cancel_event = cancel_manager.get_current_cancel_event()
|
98
|
+
|
90
99
|
counter = {"stdout": 0, "stderr": 0}
|
91
100
|
stdout_thread = threading.Thread(
|
92
101
|
target=self._stream_output,
|
@@ -112,6 +121,14 @@ class RunBashCommandTool(ToolBase):
|
|
112
121
|
stderr_thread.start()
|
113
122
|
try:
|
114
123
|
return_code = process.wait(timeout=timeout)
|
124
|
+
# Check if cancelled
|
125
|
+
if self._cancel_event and self._cancel_event.is_set():
|
126
|
+
process.kill()
|
127
|
+
self.report_warning(
|
128
|
+
tr("Command cancelled by user"),
|
129
|
+
ReportAction.EXECUTE,
|
130
|
+
)
|
131
|
+
return tr("Command cancelled by user")
|
115
132
|
except subprocess.TimeoutExpired:
|
116
133
|
process.kill()
|
117
134
|
self.report_error(
|
@@ -124,8 +141,12 @@ class RunBashCommandTool(ToolBase):
|
|
124
141
|
return tr(
|
125
142
|
"Command timed out after {timeout} seconds.", timeout=timeout
|
126
143
|
)
|
127
|
-
|
128
|
-
|
144
|
+
finally:
|
145
|
+
# Ensure threads are stopped
|
146
|
+
if self._cancel_event:
|
147
|
+
self._cancel_event.set()
|
148
|
+
stdout_thread.join(timeout=0.1)
|
149
|
+
stderr_thread.join(timeout=0.1)
|
129
150
|
stdout_file.flush()
|
130
151
|
stderr_file.flush()
|
131
152
|
if not silent:
|
@@ -71,6 +71,9 @@ class RunPowershellCommandTool(ToolBase):
|
|
71
71
|
|
72
72
|
def _stream_output(self, stream, file_obj, report_func, count_func, counter):
|
73
73
|
for line in stream:
|
74
|
+
# Check for cancellation
|
75
|
+
if hasattr(self, '_cancel_event') and self._cancel_event.is_set():
|
76
|
+
break
|
74
77
|
file_obj.write(line)
|
75
78
|
file_obj.flush()
|
76
79
|
report_func(line.rstrip("\r\n"), ReportAction.EXECUTE)
|
@@ -163,6 +166,11 @@ class RunPowershellCommandTool(ToolBase):
|
|
163
166
|
encoding="utf-8",
|
164
167
|
) as stderr_file,
|
165
168
|
):
|
169
|
+
# Set up cancellation event
|
170
|
+
from janito.llm.cancellation_manager import get_cancellation_manager
|
171
|
+
cancel_manager = get_cancellation_manager()
|
172
|
+
self._cancel_event = cancel_manager.get_current_cancel_event()
|
173
|
+
|
166
174
|
process = self._launch_process(shell_exe, command_with_encoding)
|
167
175
|
counter = {"stdout": 0, "stderr": 0}
|
168
176
|
stdout_thread = threading.Thread(
|
@@ -189,6 +197,14 @@ class RunPowershellCommandTool(ToolBase):
|
|
189
197
|
stderr_thread.start()
|
190
198
|
try:
|
191
199
|
return_code = process.wait(timeout=timeout)
|
200
|
+
# Check if cancelled
|
201
|
+
if self._cancel_event and self._cancel_event.is_set():
|
202
|
+
process.kill()
|
203
|
+
self.report_warning(
|
204
|
+
tr("Command cancelled by user"),
|
205
|
+
ReportAction.EXECUTE,
|
206
|
+
)
|
207
|
+
return tr("Command cancelled by user")
|
192
208
|
except subprocess.TimeoutExpired:
|
193
209
|
process.kill()
|
194
210
|
self.report_error(
|
@@ -93,6 +93,9 @@ class PythonCodeRun(ToolBase):
|
|
93
93
|
def stream_output(stream, file_obj, report_func, count_func):
|
94
94
|
nonlocal stdout_lines, stderr_lines
|
95
95
|
for line in stream:
|
96
|
+
# Check for cancellation
|
97
|
+
if hasattr(self, '_cancel_event') and self._cancel_event.is_set():
|
98
|
+
break
|
96
99
|
file_obj.write(line)
|
97
100
|
file_obj.flush()
|
98
101
|
report_func(line.rstrip("\r\n"))
|
@@ -101,6 +104,11 @@ class PythonCodeRun(ToolBase):
|
|
101
104
|
else:
|
102
105
|
stderr_lines += 1
|
103
106
|
|
107
|
+
# Set up cancellation event
|
108
|
+
from janito.llm.cancellation_manager import get_cancellation_manager
|
109
|
+
cancel_manager = get_cancellation_manager()
|
110
|
+
self._cancel_event = cancel_manager.get_current_cancel_event()
|
111
|
+
|
104
112
|
stdout_thread = threading.Thread(
|
105
113
|
target=stream_output,
|
106
114
|
args=(process.stdout, stdout_file, self.report_stdout, "stdout"),
|
@@ -111,10 +119,18 @@ class PythonCodeRun(ToolBase):
|
|
111
119
|
)
|
112
120
|
stdout_thread.start()
|
113
121
|
stderr_thread.start()
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
122
|
+
|
123
|
+
try:
|
124
|
+
process.stdin.write(code)
|
125
|
+
process.stdin.close()
|
126
|
+
stdout_thread.join()
|
127
|
+
stderr_thread.join()
|
128
|
+
except Exception as e:
|
129
|
+
# Handle cancellation or other errors
|
130
|
+
if self._cancel_event and self._cancel_event.is_set():
|
131
|
+
process.kill()
|
132
|
+
self.report_warning(tr("Code execution cancelled by user"), ReportAction.EXECUTE)
|
133
|
+
raise
|
118
134
|
return stdout_lines, stderr_lines
|
119
135
|
|
120
136
|
def _wait_for_process(self, process, timeout):
|
@@ -92,6 +92,9 @@ class PythonCommandRun(ToolBase):
|
|
92
92
|
def stream_output(stream, file_obj, report_func, count_func):
|
93
93
|
nonlocal stdout_lines, stderr_lines
|
94
94
|
for line in stream:
|
95
|
+
# Check for cancellation
|
96
|
+
if hasattr(self, '_cancel_event') and self._cancel_event.is_set():
|
97
|
+
break
|
95
98
|
file_obj.write(line)
|
96
99
|
file_obj.flush()
|
97
100
|
from janito.tools.tool_base import ReportAction
|
@@ -102,6 +105,11 @@ class PythonCommandRun(ToolBase):
|
|
102
105
|
else:
|
103
106
|
stderr_lines += 1
|
104
107
|
|
108
|
+
# Set up cancellation event
|
109
|
+
from janito.llm.cancellation_manager import get_cancellation_manager
|
110
|
+
cancel_manager = get_cancellation_manager()
|
111
|
+
self._cancel_event = cancel_manager.get_current_cancel_event()
|
112
|
+
|
105
113
|
stdout_thread = threading.Thread(
|
106
114
|
target=stream_output,
|
107
115
|
args=(process.stdout, stdout_file, self.report_stdout, "stdout"),
|
@@ -112,8 +120,16 @@ class PythonCommandRun(ToolBase):
|
|
112
120
|
)
|
113
121
|
stdout_thread.start()
|
114
122
|
stderr_thread.start()
|
115
|
-
|
116
|
-
|
123
|
+
|
124
|
+
try:
|
125
|
+
stdout_thread.join()
|
126
|
+
stderr_thread.join()
|
127
|
+
except Exception as e:
|
128
|
+
# Handle cancellation
|
129
|
+
if self._cancel_event and self._cancel_event.is_set():
|
130
|
+
process.kill()
|
131
|
+
self.report_warning(tr("Code execution cancelled by user"), ReportAction.EXECUTE)
|
132
|
+
raise
|
117
133
|
return stdout_lines, stderr_lines
|
118
134
|
|
119
135
|
def _wait_for_process(self, process, timeout):
|
@@ -92,6 +92,9 @@ class PythonFileRun(ToolBase):
|
|
92
92
|
def stream_output(stream, file_obj, report_func, count_func):
|
93
93
|
nonlocal stdout_lines, stderr_lines
|
94
94
|
for line in stream:
|
95
|
+
# Check for cancellation
|
96
|
+
if hasattr(self, '_cancel_event') and self._cancel_event.is_set():
|
97
|
+
break
|
95
98
|
file_obj.write(line)
|
96
99
|
file_obj.flush()
|
97
100
|
# Always supply a default action for stdout/stderr reporting
|
@@ -103,6 +106,11 @@ class PythonFileRun(ToolBase):
|
|
103
106
|
else:
|
104
107
|
stderr_lines += 1
|
105
108
|
|
109
|
+
# Set up cancellation event
|
110
|
+
from janito.llm.cancellation_manager import get_cancellation_manager
|
111
|
+
cancel_manager = get_cancellation_manager()
|
112
|
+
self._cancel_event = cancel_manager.get_current_cancel_event()
|
113
|
+
|
106
114
|
stdout_thread = threading.Thread(
|
107
115
|
target=stream_output,
|
108
116
|
args=(process.stdout, stdout_file, self.report_stdout, "stdout"),
|
@@ -113,8 +121,16 @@ class PythonFileRun(ToolBase):
|
|
113
121
|
)
|
114
122
|
stdout_thread.start()
|
115
123
|
stderr_thread.start()
|
116
|
-
|
117
|
-
|
124
|
+
|
125
|
+
try:
|
126
|
+
stdout_thread.join()
|
127
|
+
stderr_thread.join()
|
128
|
+
except Exception as e:
|
129
|
+
# Handle cancellation
|
130
|
+
if self._cancel_event and self._cancel_event.is_set():
|
131
|
+
process.kill()
|
132
|
+
self.report_warning(tr("File execution cancelled by user"), ReportAction.EXECUTE)
|
133
|
+
raise
|
118
134
|
return stdout_lines, stderr_lines
|
119
135
|
|
120
136
|
def _wait_for_process(self, process, timeout):
|
@@ -192,13 +192,10 @@ janito/plugins/core/imagedisplay/tools/__init__.py,sha256=z4xyfhiLUYaHBzus1AxaAW
|
|
192
192
|
janito/plugins/core/imagedisplay/tools/show_image.py,sha256=NpQTCMfBZ4NM6DpMe0lTJYH4NHkBCruUR11E4SdLCUw,3095
|
193
193
|
janito/plugins/core/imagedisplay/tools/show_image_grid.py,sha256=ZsTbDCBr38xYXbbAJBgRKTLuAOw-_C8799LwHA-1yYQ,3078
|
194
194
|
janito/plugins/core/system/__init__.py,sha256=tuaUFus8jTljReloESjdYFWXIEfSEYDct59I-4gZAyc,584
|
195
|
-
janito/plugins/core/system/tools/run_bash_command.py,sha256=
|
196
|
-
janito/plugins/core/system/tools/run_powershell_command.py,sha256=
|
195
|
+
janito/plugins/core/system/tools/run_bash_command.py,sha256=oxDbsLHkznN7WhW4WzIblABk27onJ5EgpAlzyrJ3AfU,9020
|
196
|
+
janito/plugins/core/system/tools/run_powershell_command.py,sha256=gWviIUtZvRUgde9TN_kUqYeseyVpsFmOJPMWLOb9_Nw,10152
|
197
197
|
janito/plugins/dev/__init__.py,sha256=V7wIaP_LMGBtg6ldz5fmiWf0eL-lSz4vcFgZjKcHAZo,136
|
198
198
|
janito/plugins/dev/pythondev/__init__.py,sha256=qAO8Ub1lwBAMcfIt6oX0clTTB2msjIIJNHBRZczhHy8,991
|
199
|
-
janito/plugins/dev/pythondev/tools/python_code_run.py,sha256=HdDuiRb7Fd7WC6bFS292XnSI1EYhn9XKlh8Hs_4Cz8E,6981
|
200
|
-
janito/plugins/dev/pythondev/tools/python_command_run.py,sha256=BT9emL3PsNGupkENNfUymPECiQEAm9tBhniCaOuatj0,6935
|
201
|
-
janito/plugins/dev/pythondev/tools/python_file_run.py,sha256=p0iOoxByCoKqW7QqfxTdHbPbRzEd_KWyZqnzrSb1qLQ,6859
|
202
199
|
janito/plugins/dev/visualization/__init__.py,sha256=2zJuePRWKBzuC1_XHg3cguh-JGh4GcvkdENUV3xplz4,547
|
203
200
|
janito/plugins/dev/visualization/tools/read_chart.py,sha256=qQebp_MEE_x2AL_pl85uA58A4lbhLQsyGl7wiG_Cjhc,10411
|
204
201
|
janito/plugins/tools/__init__.py,sha256=vNqUVWA0guwAYuPgdmiDsjmgibj9siP0e61pfTHZ8-8,271
|
@@ -214,9 +211,9 @@ janito/plugins/tools/find_files.py,sha256=S4CLC-WmifyEIO7B1Mk52TAEpy4fIFr9GW9QVQ
|
|
214
211
|
janito/plugins/tools/move_file.py,sha256=IgBTH2V3z83K3HT0cHWxAag-E5FoUTKS5nJa-_akvvs,4685
|
215
212
|
janito/plugins/tools/open_html_in_browser.py,sha256=82ONg0OSo_8puznWbrgaiZSyBK_G-TejYgsDQM8a2KU,2091
|
216
213
|
janito/plugins/tools/open_url.py,sha256=X-fdPCTkJ5WBkNDAjV_XVUh3MDEuDGcv-5PbvfC8y68,1542
|
217
|
-
janito/plugins/tools/python_code_run.py,sha256=
|
218
|
-
janito/plugins/tools/python_command_run.py,sha256=
|
219
|
-
janito/plugins/tools/python_file_run.py,sha256=
|
214
|
+
janito/plugins/tools/python_code_run.py,sha256=BIc7hPTsEqsCo3BTZviVZjoj8baQE9wNz7pQLUT8HFI,7715
|
215
|
+
janito/plugins/tools/python_command_run.py,sha256=nbXxuoDADPw5wR5ysNm5tIwFN9RrrshoQISBscXd_Ow,7645
|
216
|
+
janito/plugins/tools/python_file_run.py,sha256=jIbzBwjAHLY2xy2crQpdFj9KH3VjaD4qc7TxbkeNW88,7569
|
220
217
|
janito/plugins/tools/read_chart.py,sha256=8KT-Zzfpdp68QN6Pl8enDLPrKRBY2lhcKsJ8scS6i3o,10401
|
221
218
|
janito/plugins/tools/read_files.py,sha256=7RVj4qescT__VHe1k_VdnpHKHY5YeG0fqPiNIopd3Is,2319
|
222
219
|
janito/plugins/tools/remove_directory.py,sha256=jmY0pSrOJVQqR-_P7OuZijovAKkNB5cDk8BAAKVvvLI,1903
|
@@ -328,9 +325,9 @@ janito/tools/url_whitelist.py,sha256=0CPLkHTp5HgnwgjxwgXnJmwPeZQ30q4j3YjW59hiUUE
|
|
328
325
|
janito/tools/adapters/__init__.py,sha256=H25uYM2ETMLKpKPPEPAu9-AFjxkKfSyfx3pnoXSQlVA,255
|
329
326
|
janito/tools/adapters/local/__init__.py,sha256=1DVnka4iEQp8Xrs7rJVVx45fPpuVahjTFmuJhv-gN8s,249
|
330
327
|
janito/tools/adapters/local/adapter.py,sha256=u4nLHTaYdwZXMi1J8lsKvlG6rOmdq9xjey_3zeyCG4k,8707
|
331
|
-
janito-3.5.
|
332
|
-
janito-3.5.
|
333
|
-
janito-3.5.
|
334
|
-
janito-3.5.
|
335
|
-
janito-3.5.
|
336
|
-
janito-3.5.
|
328
|
+
janito-3.5.1.dist-info/licenses/LICENSE,sha256=dXV4fOF2ZErugtN8l_Nrj5tsRTYgtjE3cgiya0UfBio,11356
|
329
|
+
janito-3.5.1.dist-info/METADATA,sha256=1r4YjdQ2OvewXvPBmWjeog5ssJCkjZR_xFgEO_gkJzI,6093
|
330
|
+
janito-3.5.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
331
|
+
janito-3.5.1.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
|
332
|
+
janito-3.5.1.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
|
333
|
+
janito-3.5.1.dist-info/RECORD,,
|
@@ -1,172 +0,0 @@
|
|
1
|
-
import subprocess
|
2
|
-
import os
|
3
|
-
import sys
|
4
|
-
import tempfile
|
5
|
-
import threading
|
6
|
-
from janito.tools.tool_base import ToolBase, ToolPermissions
|
7
|
-
from janito.report_events import ReportAction
|
8
|
-
from janito.tools.adapters.local.adapter import register_local_tool
|
9
|
-
from janito.i18n import tr
|
10
|
-
|
11
|
-
|
12
|
-
@register_local_tool
|
13
|
-
class PythonCodeRunTool(ToolBase):
|
14
|
-
"""
|
15
|
-
Tool to execute Python code by passing it to the interpreter via standard input (stdin).
|
16
|
-
|
17
|
-
Args:
|
18
|
-
code (str): The Python code to execute as a string.
|
19
|
-
timeout (int): Timeout in seconds for the command. Defaults to 60.
|
20
|
-
silent (bool): If True, suppresses progress and status messages. Defaults to False.
|
21
|
-
|
22
|
-
Returns:
|
23
|
-
str: Output and status message, or file paths/line counts if output is large.
|
24
|
-
"""
|
25
|
-
|
26
|
-
permissions = ToolPermissions(execute=True)
|
27
|
-
tool_name = "python_code_run"
|
28
|
-
|
29
|
-
def run(self, code: str, timeout: int = 60, silent: bool = False) -> str:
|
30
|
-
if not code.strip():
|
31
|
-
self.report_warning(tr("ℹ️ Empty code provided."), ReportAction.EXECUTE)
|
32
|
-
return tr("Warning: Empty code provided. Operation skipped.")
|
33
|
-
if not silent:
|
34
|
-
self.report_action(
|
35
|
-
tr("⚡ Running: python (stdin mode) ...\n{code}\n", code=code),
|
36
|
-
ReportAction.EXECUTE,
|
37
|
-
)
|
38
|
-
self.report_stdout("\n")
|
39
|
-
else:
|
40
|
-
self.report_action(tr("⚡ Executing..."), ReportAction.EXECUTE)
|
41
|
-
try:
|
42
|
-
with (
|
43
|
-
tempfile.NamedTemporaryFile(
|
44
|
-
mode="w+",
|
45
|
-
prefix="python_stdin_stdout_",
|
46
|
-
delete=False,
|
47
|
-
encoding="utf-8",
|
48
|
-
) as stdout_file,
|
49
|
-
tempfile.NamedTemporaryFile(
|
50
|
-
mode="w+",
|
51
|
-
prefix="python_stdin_stderr_",
|
52
|
-
delete=False,
|
53
|
-
encoding="utf-8",
|
54
|
-
) as stderr_file,
|
55
|
-
):
|
56
|
-
process = subprocess.Popen(
|
57
|
-
[sys.executable],
|
58
|
-
stdin=subprocess.PIPE,
|
59
|
-
stdout=subprocess.PIPE,
|
60
|
-
stderr=subprocess.PIPE,
|
61
|
-
text=True,
|
62
|
-
bufsize=1,
|
63
|
-
universal_newlines=True,
|
64
|
-
encoding="utf-8",
|
65
|
-
env={**os.environ, "PYTHONIOENCODING": "utf-8"},
|
66
|
-
)
|
67
|
-
stdout_lines, stderr_lines = self._stream_process_output(
|
68
|
-
process, stdout_file, stderr_file, code
|
69
|
-
)
|
70
|
-
return_code = self._wait_for_process(process, timeout)
|
71
|
-
if return_code is None:
|
72
|
-
return tr(
|
73
|
-
"Code timed out after {timeout} seconds.", timeout=timeout
|
74
|
-
)
|
75
|
-
stdout_file.flush()
|
76
|
-
stderr_file.flush()
|
77
|
-
if not silent:
|
78
|
-
self.report_success(
|
79
|
-
tr("✅ Return code {return_code}", return_code=return_code),
|
80
|
-
ReportAction.EXECUTE,
|
81
|
-
)
|
82
|
-
return self._format_result(
|
83
|
-
stdout_file.name, stderr_file.name, return_code
|
84
|
-
)
|
85
|
-
except Exception as e:
|
86
|
-
self.report_error(tr("❌ Error: {error}", error=e), ReportAction.EXECUTE)
|
87
|
-
return tr("Error running code via stdin: {error}", error=e)
|
88
|
-
|
89
|
-
def _stream_process_output(self, process, stdout_file, stderr_file, code):
|
90
|
-
stdout_lines = 0
|
91
|
-
stderr_lines = 0
|
92
|
-
|
93
|
-
def stream_output(stream, file_obj, report_func, count_func):
|
94
|
-
nonlocal stdout_lines, stderr_lines
|
95
|
-
for line in stream:
|
96
|
-
file_obj.write(line)
|
97
|
-
file_obj.flush()
|
98
|
-
report_func(line.rstrip("\r\n"))
|
99
|
-
if count_func == "stdout":
|
100
|
-
stdout_lines += 1
|
101
|
-
else:
|
102
|
-
stderr_lines += 1
|
103
|
-
|
104
|
-
stdout_thread = threading.Thread(
|
105
|
-
target=stream_output,
|
106
|
-
args=(process.stdout, stdout_file, self.report_stdout, "stdout"),
|
107
|
-
)
|
108
|
-
stderr_thread = threading.Thread(
|
109
|
-
target=stream_output,
|
110
|
-
args=(process.stderr, stderr_file, self.report_stderr, "stderr"),
|
111
|
-
)
|
112
|
-
stdout_thread.start()
|
113
|
-
stderr_thread.start()
|
114
|
-
process.stdin.write(code)
|
115
|
-
process.stdin.close()
|
116
|
-
stdout_thread.join()
|
117
|
-
stderr_thread.join()
|
118
|
-
return stdout_lines, stderr_lines
|
119
|
-
|
120
|
-
def _wait_for_process(self, process, timeout):
|
121
|
-
try:
|
122
|
-
return process.wait(timeout=timeout)
|
123
|
-
except subprocess.TimeoutExpired:
|
124
|
-
process.kill()
|
125
|
-
self.report_error(
|
126
|
-
tr("❌ Timed out after {timeout} seconds.", timeout=timeout),
|
127
|
-
ReportAction.EXECUTE,
|
128
|
-
)
|
129
|
-
return None
|
130
|
-
|
131
|
-
def _format_result(self, stdout_file_name, stderr_file_name, return_code):
|
132
|
-
with open(stdout_file_name, "r", encoding="utf-8", errors="replace") as out_f:
|
133
|
-
stdout_content = out_f.read()
|
134
|
-
with open(stderr_file_name, "r", encoding="utf-8", errors="replace") as err_f:
|
135
|
-
stderr_content = err_f.read()
|
136
|
-
max_lines = 100
|
137
|
-
stdout_lines = stdout_content.count("\n")
|
138
|
-
stderr_lines = stderr_content.count("\n")
|
139
|
-
|
140
|
-
def head_tail(text, n=10):
|
141
|
-
lines = text.splitlines()
|
142
|
-
if len(lines) <= 2 * n:
|
143
|
-
return "\n".join(lines)
|
144
|
-
return "\n".join(
|
145
|
-
lines[:n]
|
146
|
-
+ ["... ({} lines omitted) ...".format(len(lines) - 2 * n)]
|
147
|
-
+ lines[-n:]
|
148
|
-
)
|
149
|
-
|
150
|
-
if stdout_lines <= max_lines and stderr_lines <= max_lines:
|
151
|
-
result = f"Return code: {return_code}\n--- python_code_run: STDOUT ---\n{stdout_content}"
|
152
|
-
if stderr_content.strip():
|
153
|
-
result += f"\n--- python_code_run: STDERR ---\n{stderr_content}"
|
154
|
-
return result
|
155
|
-
else:
|
156
|
-
result = f"stdout_file: {stdout_file_name} (lines: {stdout_lines})\n"
|
157
|
-
if stderr_lines > 0 and stderr_content.strip():
|
158
|
-
result += f"stderr_file: {stderr_file_name} (lines: {stderr_lines})\n"
|
159
|
-
result += f"returncode: {return_code}\n"
|
160
|
-
result += (
|
161
|
-
"--- python_code_run: STDOUT (head/tail) ---\n"
|
162
|
-
+ head_tail(stdout_content)
|
163
|
-
+ "\n"
|
164
|
-
)
|
165
|
-
if stderr_content.strip():
|
166
|
-
result += (
|
167
|
-
"--- python_code_run: STDERR (head/tail) ---\n"
|
168
|
-
+ head_tail(stderr_content)
|
169
|
-
+ "\n"
|
170
|
-
)
|
171
|
-
result += "Use the view_file tool to inspect the contents of these files when needed."
|
172
|
-
return result
|
@@ -1,171 +0,0 @@
|
|
1
|
-
import subprocess
|
2
|
-
import os
|
3
|
-
import sys
|
4
|
-
import tempfile
|
5
|
-
import threading
|
6
|
-
from janito.tools.tool_base import ToolBase, ToolPermissions
|
7
|
-
from janito.report_events import ReportAction
|
8
|
-
from janito.tools.adapters.local.adapter import register_local_tool
|
9
|
-
from janito.i18n import tr
|
10
|
-
|
11
|
-
|
12
|
-
@register_local_tool
|
13
|
-
class PythonCommandRunTool(ToolBase):
|
14
|
-
"""
|
15
|
-
Tool to execute Python code using the `python -c` command-line flag.
|
16
|
-
|
17
|
-
Args:
|
18
|
-
code (str): The Python code to execute as a string.
|
19
|
-
timeout (int): Timeout in seconds for the command. Defaults to 60.
|
20
|
-
silent (bool): If True, suppresses progress and status messages. Defaults to False.
|
21
|
-
|
22
|
-
Returns:
|
23
|
-
str: Output and status message, or file paths/line counts if output is large.
|
24
|
-
"""
|
25
|
-
|
26
|
-
permissions = ToolPermissions(execute=True)
|
27
|
-
tool_name = "python_command_run"
|
28
|
-
|
29
|
-
def run(self, code: str, timeout: int = 60, silent: bool = False) -> str:
|
30
|
-
if not code.strip():
|
31
|
-
self.report_warning(tr("ℹ️ Empty code provided."), ReportAction.EXECUTE)
|
32
|
-
return tr("Warning: Empty code provided. Operation skipped.")
|
33
|
-
if not silent:
|
34
|
-
self.report_action(
|
35
|
-
tr("🐍 Running: python -c ...\n{code}\n", code=code),
|
36
|
-
ReportAction.EXECUTE,
|
37
|
-
)
|
38
|
-
self.report_stdout("\n")
|
39
|
-
else:
|
40
|
-
self.report_action(tr("⚡ Executing..."), ReportAction.EXECUTE)
|
41
|
-
try:
|
42
|
-
with (
|
43
|
-
tempfile.NamedTemporaryFile(
|
44
|
-
mode="w+",
|
45
|
-
prefix="python_cmd_stdout_",
|
46
|
-
delete=False,
|
47
|
-
encoding="utf-8",
|
48
|
-
) as stdout_file,
|
49
|
-
tempfile.NamedTemporaryFile(
|
50
|
-
mode="w+",
|
51
|
-
prefix="python_cmd_stderr_",
|
52
|
-
delete=False,
|
53
|
-
encoding="utf-8",
|
54
|
-
) as stderr_file,
|
55
|
-
):
|
56
|
-
process = subprocess.Popen(
|
57
|
-
[sys.executable, "-c", code],
|
58
|
-
stdout=subprocess.PIPE,
|
59
|
-
stderr=subprocess.PIPE,
|
60
|
-
text=True,
|
61
|
-
bufsize=1,
|
62
|
-
universal_newlines=True,
|
63
|
-
encoding="utf-8",
|
64
|
-
env={**os.environ, "PYTHONIOENCODING": "utf-8"},
|
65
|
-
)
|
66
|
-
stdout_lines, stderr_lines = self._stream_process_output(
|
67
|
-
process, stdout_file, stderr_file
|
68
|
-
)
|
69
|
-
return_code = self._wait_for_process(process, timeout)
|
70
|
-
if return_code is None:
|
71
|
-
return tr(
|
72
|
-
"Code timed out after {timeout} seconds.", timeout=timeout
|
73
|
-
)
|
74
|
-
stdout_file.flush()
|
75
|
-
stderr_file.flush()
|
76
|
-
if not silent:
|
77
|
-
self.report_success(
|
78
|
-
tr("✅ Return code {return_code}", return_code=return_code),
|
79
|
-
ReportAction.EXECUTE,
|
80
|
-
)
|
81
|
-
return self._format_result(
|
82
|
-
stdout_file.name, stderr_file.name, return_code
|
83
|
-
)
|
84
|
-
except Exception as e:
|
85
|
-
self.report_error(tr("❌ Error: {error}", error=e), ReportAction.EXECUTE)
|
86
|
-
return tr("Error running code: {error}", error=e)
|
87
|
-
|
88
|
-
def _stream_process_output(self, process, stdout_file, stderr_file):
|
89
|
-
stdout_lines = 0
|
90
|
-
stderr_lines = 0
|
91
|
-
|
92
|
-
def stream_output(stream, file_obj, report_func, count_func):
|
93
|
-
nonlocal stdout_lines, stderr_lines
|
94
|
-
for line in stream:
|
95
|
-
file_obj.write(line)
|
96
|
-
file_obj.flush()
|
97
|
-
from janito.tools.tool_base import ReportAction
|
98
|
-
|
99
|
-
report_func(line.rstrip("\r\n"), ReportAction.EXECUTE)
|
100
|
-
if count_func == "stdout":
|
101
|
-
stdout_lines += 1
|
102
|
-
else:
|
103
|
-
stderr_lines += 1
|
104
|
-
|
105
|
-
stdout_thread = threading.Thread(
|
106
|
-
target=stream_output,
|
107
|
-
args=(process.stdout, stdout_file, self.report_stdout, "stdout"),
|
108
|
-
)
|
109
|
-
stderr_thread = threading.Thread(
|
110
|
-
target=stream_output,
|
111
|
-
args=(process.stderr, stderr_file, self.report_stderr, "stderr"),
|
112
|
-
)
|
113
|
-
stdout_thread.start()
|
114
|
-
stderr_thread.start()
|
115
|
-
stdout_thread.join()
|
116
|
-
stderr_thread.join()
|
117
|
-
return stdout_lines, stderr_lines
|
118
|
-
|
119
|
-
def _wait_for_process(self, process, timeout):
|
120
|
-
try:
|
121
|
-
return process.wait(timeout=timeout)
|
122
|
-
except subprocess.TimeoutExpired:
|
123
|
-
process.kill()
|
124
|
-
self.report_error(
|
125
|
-
tr("❌ Timed out after {timeout} seconds.", timeout=timeout),
|
126
|
-
ReportAction.EXECUTE,
|
127
|
-
)
|
128
|
-
return None
|
129
|
-
|
130
|
-
def _format_result(self, stdout_file_name, stderr_file_name, return_code):
|
131
|
-
with open(stdout_file_name, "r", encoding="utf-8", errors="replace") as out_f:
|
132
|
-
stdout_content = out_f.read()
|
133
|
-
with open(stderr_file_name, "r", encoding="utf-8", errors="replace") as err_f:
|
134
|
-
stderr_content = err_f.read()
|
135
|
-
max_lines = 100
|
136
|
-
stdout_lines = stdout_content.count("\n")
|
137
|
-
stderr_lines = stderr_content.count("\n")
|
138
|
-
|
139
|
-
def head_tail(text, n=10):
|
140
|
-
lines = text.splitlines()
|
141
|
-
if len(lines) <= 2 * n:
|
142
|
-
return "\n".join(lines)
|
143
|
-
return "\n".join(
|
144
|
-
lines[:n]
|
145
|
-
+ ["... ({} lines omitted) ...".format(len(lines) - 2 * n)]
|
146
|
-
+ lines[-n:]
|
147
|
-
)
|
148
|
-
|
149
|
-
if stdout_lines <= max_lines and stderr_lines <= max_lines:
|
150
|
-
result = f"Return code: {return_code}\n--- python_command_run: STDOUT ---\n{stdout_content}"
|
151
|
-
if stderr_content.strip():
|
152
|
-
result += f"\n--- python_command_run: STDERR ---\n{stderr_content}"
|
153
|
-
return result
|
154
|
-
else:
|
155
|
-
result = f"stdout_file: {stdout_file_name} (lines: {stdout_lines})\n"
|
156
|
-
if stderr_lines > 0 and stderr_content.strip():
|
157
|
-
result += f"stderr_file: {stderr_file_name} (lines: {stderr_lines})\n"
|
158
|
-
result += f"returncode: {return_code}\n"
|
159
|
-
result += (
|
160
|
-
"--- python_command_run: STDOUT (head/tail) ---\n"
|
161
|
-
+ head_tail(stdout_content)
|
162
|
-
+ "\n"
|
163
|
-
)
|
164
|
-
if stderr_content.strip():
|
165
|
-
result += (
|
166
|
-
"--- python_command_run: STDERR (head/tail) ---\n"
|
167
|
-
+ head_tail(stderr_content)
|
168
|
-
+ "\n"
|
169
|
-
)
|
170
|
-
result += "Use the view_file tool to inspect the contents of these files when needed."
|
171
|
-
return result
|
@@ -1,172 +0,0 @@
|
|
1
|
-
import subprocess
|
2
|
-
import os
|
3
|
-
import sys
|
4
|
-
import tempfile
|
5
|
-
import threading
|
6
|
-
from janito.tools.tool_base import ToolBase, ToolPermissions
|
7
|
-
from janito.report_events import ReportAction
|
8
|
-
from janito.tools.adapters.local.adapter import register_local_tool
|
9
|
-
from janito.i18n import tr
|
10
|
-
|
11
|
-
|
12
|
-
@register_local_tool
|
13
|
-
class PythonFileRunTool(ToolBase):
|
14
|
-
"""
|
15
|
-
Tool to execute a specified Python script file.
|
16
|
-
|
17
|
-
Args:
|
18
|
-
path (str): Path to the Python script file to execute.
|
19
|
-
timeout (int): Timeout in seconds for the command. Defaults to 60.
|
20
|
-
silent (bool): If True, suppresses progress and status messages. Defaults to False.
|
21
|
-
|
22
|
-
Returns:
|
23
|
-
str: Output and status message, or file paths/line counts if output is large.
|
24
|
-
"""
|
25
|
-
|
26
|
-
permissions = ToolPermissions(execute=True)
|
27
|
-
tool_name = "python_file_run"
|
28
|
-
|
29
|
-
def run(self, path: str, timeout: int = 60, silent: bool = False) -> str:
|
30
|
-
from janito.tools.path_utils import expand_path
|
31
|
-
|
32
|
-
path = expand_path(path)
|
33
|
-
if not silent:
|
34
|
-
self.report_action(
|
35
|
-
tr("🚀 Running: python {path}", path=path),
|
36
|
-
ReportAction.EXECUTE,
|
37
|
-
)
|
38
|
-
self.report_stdout("\n")
|
39
|
-
else:
|
40
|
-
self.report_action(tr("⚡ Executing..."), ReportAction.EXECUTE)
|
41
|
-
try:
|
42
|
-
with (
|
43
|
-
tempfile.NamedTemporaryFile(
|
44
|
-
mode="w+",
|
45
|
-
prefix="python_file_stdout_",
|
46
|
-
delete=False,
|
47
|
-
encoding="utf-8",
|
48
|
-
) as stdout_file,
|
49
|
-
tempfile.NamedTemporaryFile(
|
50
|
-
mode="w+",
|
51
|
-
prefix="python_file_stderr_",
|
52
|
-
delete=False,
|
53
|
-
encoding="utf-8",
|
54
|
-
) as stderr_file,
|
55
|
-
):
|
56
|
-
process = subprocess.Popen(
|
57
|
-
[sys.executable, path],
|
58
|
-
stdout=subprocess.PIPE,
|
59
|
-
stderr=subprocess.PIPE,
|
60
|
-
text=True,
|
61
|
-
bufsize=1,
|
62
|
-
universal_newlines=True,
|
63
|
-
encoding="utf-8",
|
64
|
-
env={**os.environ, "PYTHONIOENCODING": "utf-8"},
|
65
|
-
)
|
66
|
-
stdout_lines, stderr_lines = self._stream_process_output(
|
67
|
-
process, stdout_file, stderr_file
|
68
|
-
)
|
69
|
-
return_code = self._wait_for_process(process, timeout)
|
70
|
-
if return_code is None:
|
71
|
-
return tr(
|
72
|
-
"Code timed out after {timeout} seconds.", timeout=timeout
|
73
|
-
)
|
74
|
-
stdout_file.flush()
|
75
|
-
stderr_file.flush()
|
76
|
-
if not silent:
|
77
|
-
self.report_success(
|
78
|
-
tr("✅ Return code {return_code}", return_code=return_code),
|
79
|
-
ReportAction.EXECUTE,
|
80
|
-
)
|
81
|
-
return self._format_result(
|
82
|
-
stdout_file.name, stderr_file.name, return_code
|
83
|
-
)
|
84
|
-
except Exception as e:
|
85
|
-
self.report_error(tr("❌ Error: {error}", error=e), ReportAction.EXECUTE)
|
86
|
-
return tr("Error running file: {error}", error=e)
|
87
|
-
|
88
|
-
def _stream_process_output(self, process, stdout_file, stderr_file):
|
89
|
-
stdout_lines = 0
|
90
|
-
stderr_lines = 0
|
91
|
-
|
92
|
-
def stream_output(stream, file_obj, report_func, count_func):
|
93
|
-
nonlocal stdout_lines, stderr_lines
|
94
|
-
for line in stream:
|
95
|
-
file_obj.write(line)
|
96
|
-
file_obj.flush()
|
97
|
-
# Always supply a default action for stdout/stderr reporting
|
98
|
-
from janito.report_events import ReportAction
|
99
|
-
|
100
|
-
report_func(line.rstrip("\r\n"), ReportAction.EXECUTE)
|
101
|
-
if count_func == "stdout":
|
102
|
-
stdout_lines += 1
|
103
|
-
else:
|
104
|
-
stderr_lines += 1
|
105
|
-
|
106
|
-
stdout_thread = threading.Thread(
|
107
|
-
target=stream_output,
|
108
|
-
args=(process.stdout, stdout_file, self.report_stdout, "stdout"),
|
109
|
-
)
|
110
|
-
stderr_thread = threading.Thread(
|
111
|
-
target=stream_output,
|
112
|
-
args=(process.stderr, stderr_file, self.report_stderr, "stderr"),
|
113
|
-
)
|
114
|
-
stdout_thread.start()
|
115
|
-
stderr_thread.start()
|
116
|
-
stdout_thread.join()
|
117
|
-
stderr_thread.join()
|
118
|
-
return stdout_lines, stderr_lines
|
119
|
-
|
120
|
-
def _wait_for_process(self, process, timeout):
|
121
|
-
try:
|
122
|
-
return process.wait(timeout=timeout)
|
123
|
-
except subprocess.TimeoutExpired:
|
124
|
-
process.kill()
|
125
|
-
self.report_error(
|
126
|
-
tr("❌ Timed out after {timeout} seconds.", timeout=timeout),
|
127
|
-
ReportAction.EXECUTE,
|
128
|
-
)
|
129
|
-
return None
|
130
|
-
|
131
|
-
def _format_result(self, stdout_file_name, stderr_file_name, return_code):
|
132
|
-
with open(stdout_file_name, "r", encoding="utf-8", errors="replace") as out_f:
|
133
|
-
stdout_content = out_f.read()
|
134
|
-
with open(stderr_file_name, "r", encoding="utf-8", errors="replace") as err_f:
|
135
|
-
stderr_content = err_f.read()
|
136
|
-
max_lines = 100
|
137
|
-
stdout_lines = stdout_content.count("\n")
|
138
|
-
stderr_lines = stderr_content.count("\n")
|
139
|
-
|
140
|
-
def head_tail(text, n=10):
|
141
|
-
lines = text.splitlines()
|
142
|
-
if len(lines) <= 2 * n:
|
143
|
-
return "\n".join(lines)
|
144
|
-
return "\n".join(
|
145
|
-
lines[:n]
|
146
|
-
+ ["... ({} lines omitted) ...".format(len(lines) - 2 * n)]
|
147
|
-
+ lines[-n:]
|
148
|
-
)
|
149
|
-
|
150
|
-
if stdout_lines <= max_lines and stderr_lines <= max_lines:
|
151
|
-
result = f"Return code: {return_code}\n--- python_file_run: STDOUT ---\n{stdout_content}"
|
152
|
-
if stderr_content.strip():
|
153
|
-
result += f"\n--- python_file_run: STDERR ---\n{stderr_content}"
|
154
|
-
return result
|
155
|
-
else:
|
156
|
-
result = f"stdout_file: {stdout_file_name} (lines: {stdout_lines})\n"
|
157
|
-
if stderr_lines > 0 and stderr_content.strip():
|
158
|
-
result += f"stderr_file: {stderr_file_name} (lines: {stderr_lines})\n"
|
159
|
-
result += f"returncode: {return_code}\n"
|
160
|
-
result += (
|
161
|
-
"--- python_file_run: STDOUT (head/tail) ---\n"
|
162
|
-
+ head_tail(stdout_content)
|
163
|
-
+ "\n"
|
164
|
-
)
|
165
|
-
if stderr_content.strip():
|
166
|
-
result += (
|
167
|
-
"--- python_file_run: STDERR (head/tail) ---\n"
|
168
|
-
+ head_tail(stderr_content)
|
169
|
-
+ "\n"
|
170
|
-
)
|
171
|
-
result += "Use the view_file tool to inspect the contents of these files when needed."
|
172
|
-
return result
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|