shell improvements
frdel committed
Jul 4, 2025 at 22:33 UTC
07e3e59e6f969391c824c6202f0c0e33d36ae704
4 files changed
+19
-87
python/helpers/files.py
-1
@@ -12,7 +12,6 @@ import zipfile
12
import importlib
13
import importlib.util
14
import inspect
15
-from python.helpers.print_style import PrintStyle
15
16
17
class VariablesPlugin(ABC):
python/helpers/shell_ssh.py
+4
-1
@@ -41,7 +41,7 @@ class SSHInteractiveSession:
41
allow_agent=False,
42
look_for_keys=False,
43
)
44
- self.shell = self.client.invoke_shell(width=80, height=40)
44
+ self.shell = self.client.invoke_shell(width=100, height=50)
45
# self.shell.send(f'PS1="{SSHInteractiveSession.ps1_label}"'.encode())
46
# return
47
while True: # wait for end of initial output
@@ -193,6 +193,9 @@ class SSHInteractiveSession:
193
ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
194
cleaned = ansi_escape.sub("", input_string)
195
196
+ # remove null bytes
197
+ cleaned = cleaned.replace("\x00", "")
198
+
199
# Replace '\r\n' with '\n'
200
cleaned = cleaned.replace("\r\n", "\n")
201
python/tools/code_execution_tool.py
+15
-11
@@ -73,7 +73,9 @@ class CodeExecution(Tool):
73
if not text:
74
text = f"{self.name} - {self.args['runtime']}"
75
text = truncate_text_string(text, 60)
76
- return f"icon://terminal {text}"
76
+ session = self.args.get("session", None)
77
+ session_text = f"[{session}] " if session or session == 0 else ""
78
+ return f"icon://terminal {session_text}{text}"
79
80
async def after_execution(self, response, **kwargs):
81
self.agent.hist_add_tool_result(self.name, response.message)
@@ -135,22 +137,24 @@ class CodeExecution(Tool):
137
async def execute_python_code(self, session: int, code: str, reset: bool = False):
138
escaped_code = shlex.quote(code)
139
command = f"ipython -c {escaped_code}"
138
- prefix = "python> "+self.format_command_for_output(code)+"\n\n"
140
+ prefix = "python> " + self.format_command_for_output(code) + "\n\n"
141
return await self.terminal_session(session, command, reset, prefix)
142
143
async def execute_nodejs_code(self, session: int, code: str, reset: bool = False):
144
escaped_code = shlex.quote(code)
143
- command = f"node /exe/node_eval.js {escaped_code}"
144
- prefix = "node> "+self.format_command_for_output(code)+"\n\n"
145
+ command = f"node /exe/node_eval.js {escaped_code}"
146
+ prefix = "node> " + self.format_command_for_output(code) + "\n\n"
147
return await self.terminal_session(session, command, reset, prefix)
148
149
async def execute_terminal_command(
150
self, session: int, command: str, reset: bool = False
151
):
150
- prefix = "bash> "+self.format_command_for_output(command)+"\n\n"
152
+ prefix = "bash> " + self.format_command_for_output(command) + "\n\n"
153
return await self.terminal_session(session, command, reset, prefix)
154
153
- async def terminal_session(self, session: int, command: str, reset: bool = False, prefix: str = ""):
155
+ async def terminal_session(
156
+ self, session: int, command: str, reset: bool = False, prefix: str = ""
157
+ ):
158
159
await self.agent.handle_intervention() # wait for intervention and handle it, if paused
160
# try again on lost connection
@@ -205,8 +209,6 @@ class CodeExecution(Tool):
209
# final length
210
short_cmd = truncate_text_string(short_cmd, 100)
211
return f"{short_cmd}"
208
-
209
-
212
213
async def get_terminal_output(
214
self,
@@ -217,7 +219,7 @@ class CodeExecution(Tool):
219
dialog_timeout=5, # potential dialog detection timeout
220
max_exec_timeout=180, # hard cap on total runtime
221
sleep_time=0.1,
220
- prefix=""
222
+ prefix="",
223
):
224
# Common shell prompt regex patterns (add more as needed)
225
prompt_patterns = [
@@ -343,7 +345,9 @@ class CodeExecution(Tool):
345
heading = self.get_heading_from_output(
346
truncated_output, 0
347
)
346
- self.log.update(content=prefix + response, heading=heading)
348
+ self.log.update(
349
+ content=prefix + response, heading=heading
350
+ )
351
return response
352
353
async def reset_terminal(self, session=0, reason: str | None = None):
@@ -384,7 +388,7 @@ class CodeExecution(Tool):
388
389
def fix_full_output(self, output: str):
390
# remove any single byte \xXX escapes
387
- output = re.sub(r'(?<!\\)\\x[0-9A-Fa-f]{2}', '', output)
391
+ output = re.sub(r"(?<!\\)\\x[0-9A-Fa-f]{2}", "", output)
392
# Strip every line of output before truncation
393
output = "\n".join(line.strip() for line in output.splitlines())
394
output = truncate_text_agent(agent=self.agent, output=output, threshold=10000)
test.py
deleted
-74
@@ -1,74 +0,0 @@
1
-import asyncio
2
-from os import sep
3
-from langchain_core.messages import HumanMessage, SystemMessage
4
-from langchain_core.prompts import ChatPromptTemplate
5
-import models
6
-from python.helpers import dotenv
7
-
8
-
9
-async def test():
10
-
11
- dotenv.load_dotenv()
12
-
13
- # model_name = "moonshotai/kimi-dev-72b:free"
14
- # model_name = "qwen/qwq-32b"
15
- # model_name = "qwen/qwen3-32b"
16
- # model_name = "anthropic/claude-3.7-sonnet:thinking"
17
- model_name = "openai/gpt-4.1-nano"
18
- system = ""
19
- message = "hello"
20
-
21
- model = models.get_chat_model(models.ModelProvider.OPENROUTER, model_name)
22
-
23
- async def response_callback(chunk: str, full: str):
24
- if chunk == full:
25
- print("\n")
26
- print("Response:")
27
- print(chunk, end="", flush=True)
28
-
29
- async def reasoning_callback(chunk: str, full: str):
30
- if chunk == full:
31
- print("\n")
32
- print("Reasoning:")
33
- print(chunk, end="", flush=True)
34
-
35
- response, reasoning = await model.unified_call(
36
- system_message=system,
37
- user_message=message,
38
- response_callback=response_callback,
39
- reasoning_callback=reasoning_callback,
40
- )
41
-
42
- print("\n")
43
- print("Final:")
44
- print("Reasoning:", reasoning)
45
- print("Response:", response)
46
-
47
-
48
-async def test2():
49
-
50
- dotenv.load_dotenv()
51
-
52
- import initialize
53
- config = initialize.initialize_agent()
54
-
55
- model = models.get_browser_model(
56
- provider=config.browser_model.provider,
57
- name=config.browser_model.name,
58
- **config.browser_model.kwargs,
59
- )
60
-
61
- response, reasoning = await model.unified_call(
62
- system_message="",
63
- user_message="hi",
64
- )
65
-
66
- print("\n")
67
- print("Final:")
68
- print("Reasoning:", reasoning)
69
- print("Response:", response)
70
-
71
-
72
-if __name__ == "__main__":
73
- # asyncio.run(test())
74
- asyncio.run(test2())
\ No newline at end of file