69 lines
2.7 KiB
Python
69 lines
2.7 KiB
Python
import curses
|
|
from .render import init_colors, draw
|
|
from .input import handle_key
|
|
|
|
|
|
class HendrikTUI:
|
|
# State holder & orchestrator.
|
|
# Semua data UI disimpan di sini, method lain (render, input, agent)
|
|
# menerima `app` (self) sebagai parameter pertama.
|
|
def __init__(self, llm_client, tools_definition, TOOLS, TOOL_HANDLERS,
|
|
build_system_prompt, agent_max_iterations):
|
|
# -- dependencies (disuntik dari luar) --
|
|
self.llm = llm_client
|
|
self.tools_def = tools_definition
|
|
self.TOOLS = TOOLS
|
|
self.TOOL_HANDLERS = TOOL_HANDLERS
|
|
self.build_system_prompt = build_system_prompt
|
|
self.agent_max_iterations = agent_max_iterations
|
|
|
|
# -- UI state --
|
|
self.messages = None # chat history yg dikirim ke LLM API
|
|
self.log = [] # rendered log (display-only, ada timestamp)
|
|
self.input_buffer = [""] # baris-baris input multi-line
|
|
self.input_line = 0 # index baris aktif di buffer
|
|
self.input_col = 0 # kolom kursor di baris aktif
|
|
self.scroll = 0 # scroll offset chat area
|
|
self.processing = False # true saat agent sedang memproses
|
|
self.running = True # false → keluar dari main loop
|
|
self.h, self.w = 0, 0 # ukuran terminal (height, width)
|
|
|
|
def run(self):
|
|
# Masuk ke curses wrapper. wrapper() setup/teardown terminal
|
|
# dan menangani restore terminal meskipun terjadi error.
|
|
try:
|
|
curses.wrapper(self._main)
|
|
except KeyboardInterrupt:
|
|
pass
|
|
print("Exiting.")
|
|
|
|
def _main(self, stdscr):
|
|
# Main loop: draw → getch → handle
|
|
curses.use_default_colors()
|
|
init_colors()
|
|
stdscr.keypad(True) # enable key codes (KEY_UP, KEY_DOWN, dll)
|
|
stdscr.refresh()
|
|
|
|
# Init system prompt — sekali di awal
|
|
self.messages = [{"role": "system",
|
|
"content": self.build_system_prompt(self.tools_def)}]
|
|
|
|
while self.running:
|
|
self.h, self.w = stdscr.getmaxyx()
|
|
# Minimal ukuran terminal biar UI gak rusak
|
|
if self.h < 14 or self.w < 40:
|
|
stdscr.erase()
|
|
stdscr.addstr(0, 0, "Terminal too small (min 40x14)")
|
|
stdscr.refresh()
|
|
stdscr.getch()
|
|
continue
|
|
|
|
draw(self, stdscr)
|
|
# Sembunyikan kursor saat processing, tampilkan high visibility saat idle
|
|
curses.curs_set(0 if self.processing else 2)
|
|
try:
|
|
key = stdscr.getch()
|
|
except KeyboardInterrupt:
|
|
break
|
|
handle_key(self, stdscr, key)
|