import curses import threading from .render import init_colors, draw from .input import handle_key class HendrikTUI: def __init__(self, llm_client, tools_definition, TOOLS, TOOL_HANDLERS, build_system_prompt, agent_max_iterations): 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 self.messages = None self.log = [] self.input_buffer = [""] self.input_line = 0 self.input_col = 0 self.scroll = 0 self.processing = False self.running = True self.h, self.w = 0, 0 self.agent_thread: threading.Thread | None = None self.agent_done = threading.Event() def run(self): try: curses.wrapper(self._main) except KeyboardInterrupt: pass def _main(self, stdscr): curses.use_default_colors() init_colors() stdscr.keypad(True) stdscr.refresh() self.messages = [{"role": "system", "content": self.build_system_prompt(self.tools_def)}] while self.running: self.h, self.w = stdscr.getmaxyx() 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) curses.curs_set(2) if self.processing: stdscr.timeout(100) else: stdscr.timeout(-1) try: key = stdscr.getch() except KeyboardInterrupt: break handle_key(self, stdscr, key) if self.agent_done.is_set(): self.agent_thread.join() self.agent_done.clear() self.processing = False self.agent_thread = None