MCPcopy Create free account
hub / github.com/ScaleML/AgentSPEX / PersistentShell

Class PersistentShell

src/sandbox_vm/tools/session_management.py:42–106  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

40
41
42class PersistentShell:
43 def __init__(self, cwd: str, env: dict, history_lines: int = 4000):
44 self._pexpect = pexpect
45 self.proc = pexpect.spawn(
46 "/bin/bash",
47 ["-i"],
48 cwd=cwd,
49 env=env,
50 encoding="utf-8",
51 echo=False,
52 )
53 self.proc.delaybeforesend = 0
54
55 from collections import deque
56
57 self._buf = deque(maxlen=int(history_lines))
58 self._lock = threading.Lock()
59 self._stop = threading.Event()
60 self._reader = threading.Thread(
61 target=self._drain_loop, name="pexpect-drain", daemon=True
62 )
63 self._reader.start()
64 self.send("export PS1='[vs] '")
65
66 def _drain_loop(self):
67 while not self._stop.is_set():
68 try:
69 chunk = self.proc.read_nonblocking(size=4096, timeout=0.1)
70 if chunk:
71 with self._lock:
72 for line in chunk.splitlines(True):
73 self._buf.append(line)
74 except self._pexpect.TIMEOUT:
75 continue
76 except self._pexpect.EOF:
77 break
78 except Exception:
79 continue
80
81 def send(self, text: str) -> None:
82 with self._lock:
83 self.proc.sendline(text or "")
84
85 def tail(self, lines: int = 200) -> str:
86 with self._lock:
87 if lines <= 0:
88 return ""
89 return "".join(list(self._buf)[-int(lines) :])
90
91 def close(self) -> None:
92 self._stop.set()
93 try:
94 if self.proc.isalive():
95 try:
96 self.proc.sendline("exit")
97 except Exception:
98 pass
99 self.proc.close(force=True)

Callers 1

get_or_create_shellMethod · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected