Former-commit-id: eff45e88e6
huggingface
Kye 2 years ago
parent 122fd955b0
commit f5c10eb36c

@ -240,236 +240,236 @@ class ToolsFactory:
##########################################+> SYS # ##########################################+> SYS
import signal # import signal
from typing import Optional, Tuple # from typing import Optional, Tuple
from ptrace.debugger import ( # from ptrace.debugger import (
NewProcessEvent, # NewProcessEvent,
ProcessExecution, # ProcessExecution,
ProcessExit, # ProcessExit,
ProcessSignal, # ProcessSignal,
PtraceDebugger, # PtraceDebugger,
PtraceProcess, # PtraceProcess,
) # )
from ptrace.func_call import FunctionCallOptions # from ptrace.func_call import FunctionCallOptions
from ptrace.syscall import PtraceSyscall # from ptrace.syscall import PtraceSyscall
from ptrace.tools import signal_to_exitcode # from ptrace.tools import signal_to_exitcode
class SyscallTimeoutException(Exception): # class SyscallTimeoutException(Exception):
def __init__(self, pid: int, *args) -> None: # def __init__(self, pid: int, *args) -> None:
super().__init__(f"deadline exceeded while waiting syscall for {pid}", *args) # super().__init__(f"deadline exceeded while waiting syscall for {pid}", *args)
class SyscallTracer: # class SyscallTracer:
def __init__(self, pid: int): # def __init__(self, pid: int):
self.debugger: PtraceDebugger = PtraceDebugger() # self.debugger: PtraceDebugger = PtraceDebugger()
self.pid: int = pid # self.pid: int = pid
self.process: PtraceProcess = None # self.process: PtraceProcess = None
def is_waiting(self, syscall: PtraceSyscall) -> bool: # def is_waiting(self, syscall: PtraceSyscall) -> bool:
if syscall.name.startswith("wait"): # if syscall.name.startswith("wait"):
return True # return True
return False # return False
def attach(self): # def attach(self):
self.process = self.debugger.addProcess(self.pid, False) # self.process = self.debugger.addProcess(self.pid, False)
def detach(self): # def detach(self):
self.process.detach() # self.process.detach()
self.debugger.quit() # self.debugger.quit()
def set_timer(self, timeout: int): # def set_timer(self, timeout: int):
def handler(signum, frame): # def handler(signum, frame):
raise SyscallTimeoutException(self.process.pid) # raise SyscallTimeoutException(self.process.pid)
signal.signal(signal.SIGALRM, handler) # signal.signal(signal.SIGALRM, handler)
signal.alarm(timeout) # signal.alarm(timeout)
def reset_timer(self): # def reset_timer(self):
signal.alarm(0) # signal.alarm(0)
def wait_syscall_with_timeout(self, timeout: int): # def wait_syscall_with_timeout(self, timeout: int):
self.set_timer(timeout) # self.set_timer(timeout)
self.process.waitSyscall() # self.process.waitSyscall()
self.reset_timer() # self.reset_timer()
def wait_until_stop_or_exit(self) -> Tuple[Optional[int], str]: # def wait_until_stop_or_exit(self) -> Tuple[Optional[int], str]:
self.process.syscall() # self.process.syscall()
exitcode = None # exitcode = None
reason = "" # reason = ""
while True: # while True:
if not self.debugger: # if not self.debugger:
break # break
try: # try:
self.wait_syscall_with_timeout(30) # self.wait_syscall_with_timeout(30)
except ProcessExit as event: # except ProcessExit as event:
if event.exitcode is not None: # if event.exitcode is not None:
exitcode = event.exitcode # exitcode = event.exitcode
continue # continue
except ProcessSignal as event: # except ProcessSignal as event:
event.process.syscall(event.signum) # event.process.syscall(event.signum)
exitcode = signal_to_exitcode(event.signum) # exitcode = signal_to_exitcode(event.signum)
reason = event.reason # reason = event.reason
continue # continue
except NewProcessEvent as event: # except NewProcessEvent as event:
continue # continue
except ProcessExecution as event: # except ProcessExecution as event:
continue # continue
except Exception as e: # except Exception as e:
reason = str(e) # reason = str(e)
break # break
syscall = self.process.syscall_state.event( # syscall = self.process.syscall_state.event(
FunctionCallOptions( # FunctionCallOptions(
write_types=False, # write_types=False,
write_argname=False, # write_argname=False,
string_max_length=300, # string_max_length=300,
replace_socketcall=True, # replace_socketcall=True,
write_address=False, # write_address=False,
max_array_count=20, # max_array_count=20,
) # )
) # )
self.process.syscall()
if syscall is None:
continue
if syscall.result: # self.process.syscall()
continue
self.reset_timer() # if syscall is None:
# continue
return exitcode, reason # if syscall.result:
##########################################+> SYS CALL END # continue
# self.reset_timer()
# return exitcode, reason
# ##########################################+> SYS CALL END
############### => st dout.py
import os
import time
import subprocess
from datetime import datetime
from typing import Callable, Literal, Optional, Union, Tuple
PipeType = Union[Literal["stdout"], Literal["stderr"]] # ############### => st dout.py
# import os
# import time
# import subprocess
# from datetime import datetime
# from typing import Callable, Literal, Optional, Union, Tuple
class StdoutTracer: # PipeType = Union[Literal["stdout"], Literal["stderr"]]
def __init__(
self,
process: subprocess.Popen,
timeout: int = 30,
interval: int = 0.1,
on_output: Callable[[PipeType, str], None] = lambda: None,
):
self.process: subprocess.Popen = process
self.timeout: int = timeout
self.interval: int = interval
self.last_output: datetime = None
self.on_output: Callable[[PipeType, str], None] = on_output
def nonblock(self):
os.set_blocking(self.process.stdout.fileno(), False)
os.set_blocking(self.process.stderr.fileno(), False)
def get_output(self, pipe: PipeType) -> str:
output = None
if pipe == "stdout":
output = self.process.stdout.read()
elif pipe == "stderr":
output = self.process.stderr.read()
if output:
decoded = output.decode()
self.on_output(pipe, decoded)
self.last_output = datetime.now()
return decoded
return ""
def last_output_passed(self, seconds: int) -> bool:
return (datetime.now() - self.last_output).seconds > seconds
def wait_until_stop_or_exit(self) -> Tuple[Optional[int], str]:
self.nonblock()
self.last_output = datetime.now()
output = ""
exitcode = None
while True:
new_stdout = self.get_output("stdout")
if new_stdout:
output += new_stdout
new_stderr = self.get_output("stderr")
if new_stderr:
output += new_stderr
if self.process.poll() is not None:
exitcode = self.process.poll()
break
if self.last_output_passed(self.timeout):
self.process.kill()
break
time.sleep(self.interval)
return (exitcode, output) # class StdoutTracer:
# def __init__(
# self,
# process: subprocess.Popen,
# timeout: int = 30,
# interval: int = 0.1,
# on_output: Callable[[PipeType, str], None] = lambda: None,
# ):
# self.process: subprocess.Popen = process
# self.timeout: int = timeout
# self.interval: int = interval
# self.last_output: datetime = None
# self.on_output: Callable[[PipeType, str], None] = on_output
# def nonblock(self):
# os.set_blocking(self.process.stdout.fileno(), False)
# os.set_blocking(self.process.stderr.fileno(), False)
# def get_output(self, pipe: PipeType) -> str:
# output = None
# if pipe == "stdout":
# output = self.process.stdout.read()
# elif pipe == "stderr":
# output = self.process.stderr.read()
# if output:
# decoded = output.decode()
# self.on_output(pipe, decoded)
# self.last_output = datetime.now()
# return decoded
# return ""
# def last_output_passed(self, seconds: int) -> bool:
# return (datetime.now() - self.last_output).seconds > seconds
# def wait_until_stop_or_exit(self) -> Tuple[Optional[int], str]:
# self.nonblock()
# self.last_output = datetime.now()
# output = ""
# exitcode = None
# while True:
# new_stdout = self.get_output("stdout")
# if new_stdout:
# output += new_stdout
# new_stderr = self.get_output("stderr")
# if new_stderr:
# output += new_stderr
# if self.process.poll() is not None:
# exitcode = self.process.poll()
# break
# if self.last_output_passed(self.timeout):
# self.process.kill()
# break
# time.sleep(self.interval)
# return (exitcode, output)
################## => stdout end ################## => stdout end
import os # import os
import subprocess # import subprocess
import time # import time
from datetime import datetime # from datetime import datetime
from typing import Dict, List # from typing import Dict, List
from swarms.utils.main import ANSI, Color, Style # test # from swarms.utils.main import ANSI, Color, Style # test
class Terminal(BaseToolSet): # class Terminal(BaseToolSet):
def __init__(self): # def __init__(self):
self.sessions: Dict[str, List[SyscallTracer]] = {} # self.sessions: Dict[str, List[SyscallTracer]] = {}
@tool( # @tool(
name="Terminal", # name="Terminal",
description="Executes commands in a terminal." # description="Executes commands in a terminal."
"If linux errno occurs, we have to solve the problem with the terminal. " # "If linux errno occurs, we have to solve the problem with the terminal. "
"Input must be one valid command. " # "Input must be one valid command. "
"Output will be any output from running that command.", # "Output will be any output from running that command.",
scope=ToolScope.SESSION, # scope=ToolScope.SESSION,
) # )
def execute(self, commands: str, get_session: SessionGetter) -> str: # def execute(self, commands: str, get_session: SessionGetter) -> str:
session, _ = get_session() # session, _ = get_session()
try: # try:
process = subprocess.Popen( # process = subprocess.Popen(
commands, # commands,
shell=True, # shell=True,
stdout=subprocess.PIPE, # stdout=subprocess.PIPE,
stderr=subprocess.PIPE, # stderr=subprocess.PIPE,
) # )
logger.info(ANSI("Realtime Terminal Output").to(Color.magenta()) + ": ") # logger.info(ANSI("Realtime Terminal Output").to(Color.magenta()) + ": ")
output = "" # output = ""
tracer = StdoutTracer( # tracer = StdoutTracer(
process, # process,
on_output=lambda p, o: logger.info( # on_output=lambda p, o: logger.info(
ANSI(p).to(Style.dim()) + " " + o.strip("\n") # ANSI(p).to(Style.dim()) + " " + o.strip("\n")
), # ),
) # )
exitcode, output = tracer.wait_until_stop_or_exit() # exitcode, output = tracer.wait_until_stop_or_exit()
except Exception as e: # except Exception as e:
output = str(e) # output = str(e)
logger.debug( # logger.debug(
f"\nProcessed Terminal, Input Commands: {commands} " # f"\nProcessed Terminal, Input Commands: {commands} "
f"Output Answer: {output}" # f"Output Answer: {output}"
) # )
return output # return output
# if __name__ == "__main__": # if __name__ == "__main__":

Loading…
Cancel
Save