forked from AgeOfMarcus/1337GPT
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tui.py
160 lines (132 loc) · 5.19 KB
/
tui.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
from langchain.callbacks.base import BaseCallbackHandler
# rich
from rich.live import Live
from rich.table import Table, Row
from rich.json import JSON
import json, os, math
# task_manager.py
from task_manager import TaskManager
try:
if os.name == 'nt':
# windows
from msvcrt import getch as _getch
getch = lambda: _getch().decode()
else:
# linux based
from getch import getch
except ImportError as e:
lib = str(e).split("'")[1]
exit(f'This program requires the {lib} library. Please install it with `pip install {lib}`')
# by god I will turn this Table into a TUI
class TUI(object):
def __init__(self):
self.max_lines = os.get_terminal_size().lines - 12
self.total_cols = os.get_terminal_size().columns - 6
# if total_cols is odd, make it even
if self.total_cols % 2 == 1:
self.total_cols -= 1
self.half_cols = self.total_cols // 2
self.table = Table(title='1337GPT')
self.table.add_column('Data')
self.table.add_column('Console')
for i in range(self.max_lines):
self.table.add_row(' ' * self.half_cols, ' ' * self.half_cols)
self.console = Console(self)
def pad(self, text):
return text.ljust(self.half_cols)
class Console(object):
def __init__(self, tui: TUI):
self.tui = tui
self.history = []
self._input = ''
def getlines(self):
return self.tui.table.columns[1]._cells
def checklines(self, line):
chars = len(line)
if chars > self.tui.half_cols:
over = chars / self.tui.half_cols
return math.ceil(over)
return 1
def add_line(self, line):
# pad line
line = self.tui.pad(line)
_lines = self.checklines(line)
lines = self.getlines()
for i in range(_lines):
self.history.append(lines.pop(0))
lines.append(line)
self.tui.table.columns[1]._cells = lines
def print(self, *args):
self.add_line(' '.join(map(repr, args)))
def update_last(self, text):
lines = self.getlines()
lines[-1] = self.tui.pad(text)
if (_ := self.checklines(text)) > 1:
for i in range(_ - 1):
self.history.append(lines.pop(0))
self.tui.table.columns[1]._cells = lines
def input(self, prompt):
self.add_line(prompt)
while True:
ch = getch()
if ch == '\x03':
raise KeyboardInterrupt
elif ch in ('\n', '\r'):
inp = self._input
self._input = ''
return inp
elif (ord(ch) == 127) or (ch in ('\b', '\x08')):
self._input = self._input[:-1]
self.update_last(prompt + self._input)
else:
self._input += ch
self.update_last(prompt + self._input)
def update_data_from_taskman(taskman: TaskManager, tui: TUI):
data = JSON(json.dumps({
'Goal': taskman.final_goal,
'Next Task': taskman.current_tasks[0],
'Stored Info': taskman.stored_info,
'Final Result': taskman.final_result
})).text
for i, line in enumerate(data.split('\n')):
try:
tui.table.columns[0]._cells[i] = line
except IndexError:
tui.table.columns[0]._cells.append(line) # not gonna show but oh well its there
def main(taskman: TaskManager, agent, args):
tui = TUI()
taskman.output_func = tui.console.print
taskman.input_func = tui.console.input
class TUIHandler(BaseCallbackHandler):
def on_tool_start(self, tool, args, **kwargs):
tui.console.add_line(f'Starting tool [green]{tool["name"]}[/green] with args [green]{args}[/green]')
def on_tool_end(self, out, **kwargs):
tui.console.add_line(f'Tool finished with output [darkgreen]{out}[/darkgreen]')
cb_handler = TUIHandler()
taskman.verbose = False # not needed as left pane shows info
agent.verbose = False # cant redirect these outputs
# patch input func
for tool in agent.tools:
if tool.name == 'RunCommand':
tool.verbose = tui.console.input # yes this is dirty, but i cant create my own attr
with Live(tui.table, refresh_per_second=30):
# main loop
while not taskman.goal_completed:
update_data_from_taskman(taskman, tui)
if not taskman.current_tasks:
if taskman.ensure_goal_complete():
break
continue
task = taskman.current_tasks.pop(0)
tui.console.add_line(f'[grey]Next task: {task}[/grey]')
cont = tui.console.input('[blue]Continue?[/blue] \[Y]es/\[n]o/\[e]dit: ')[0].lower()
if cont == 'n':
continue
elif cont == 'e':
task = tui.console.input('[cyan]Enter task[/cyan]: ')
res = agent.run(taskman.format_task_str(
task,
smart_combine=args.use_smart_combine,
include_completed_tasks=args.include_completed_tasks
), callbacks=[cb_handler])
taskman.refine(task, res)