Update TUI
This commit is contained in:
parent
0383410c84
commit
6703468dd8
@ -76,7 +76,7 @@ ACTIONS = {
|
|||||||
},
|
},
|
||||||
"send_prompt": {
|
"send_prompt": {
|
||||||
"key": KEY_CTRL_ENTER,
|
"key": KEY_CTRL_ENTER,
|
||||||
"label": "Send Prompt", "mnemonic": "P", "shortcut": "Ctrl+Enter",
|
"label": "Send Prompt", "mnemonic": "P", "shortcut": "Ctrl+Return",
|
||||||
"handler": _send_prompt, "enabled": _ready,
|
"handler": _send_prompt, "enabled": _ready,
|
||||||
},
|
},
|
||||||
"cancel_inference": {
|
"cancel_inference": {
|
||||||
|
|||||||
@ -24,6 +24,10 @@ class HendrikTUI:
|
|||||||
self.agent_max_iterations = agent_max_iterations
|
self.agent_max_iterations = agent_max_iterations
|
||||||
self.character_name = config.AGENT_CHARACTER or "AI Agent"
|
self.character_name = config.AGENT_CHARACTER or "AI Agent"
|
||||||
|
|
||||||
|
# Nama model set aktif (dipakai status bar). Diisi dari default set
|
||||||
|
# saat startup, lalu diperbarui setiap kali user ganti model set.
|
||||||
|
self.model_set_name = self._lookup_model_set_name()
|
||||||
|
|
||||||
self.messages = None
|
self.messages = None
|
||||||
self.log = []
|
self.log = []
|
||||||
self.input_buffer = [""]
|
self.input_buffer = [""]
|
||||||
@ -47,6 +51,31 @@ class HendrikTUI:
|
|||||||
self.session_mgr = NeoSessionManager()
|
self.session_mgr = NeoSessionManager()
|
||||||
self.current_session: NeoSession | None = None
|
self.current_session: NeoSession | None = None
|
||||||
|
|
||||||
|
def _lookup_model_set_name(self) -> str:
|
||||||
|
"""Nama model set yang sedang aktif (untuk status bar).
|
||||||
|
|
||||||
|
Mulai dari default set tipe 'llm'; jika model yang sedang dipakai
|
||||||
|
ternyata milik set lain, cari set yang memuat model tersebut."""
|
||||||
|
try:
|
||||||
|
default_id = moop.get_default_set_id(None, "llm")
|
||||||
|
default_set = moop.get_set(None, default_id) if default_id else None
|
||||||
|
model = getattr(self.llm, "model", "") or ""
|
||||||
|
if default_set and (
|
||||||
|
not model
|
||||||
|
or model in {c["model"] for c in moop.resolve_chain(None, default_id)}
|
||||||
|
):
|
||||||
|
return default_set["name"] or "-"
|
||||||
|
if default_set:
|
||||||
|
for cand in moop.list_sets(None):
|
||||||
|
if cand["id"] == default_id:
|
||||||
|
continue
|
||||||
|
if model in {c["model"] for c in moop.resolve_chain(None, cand["id"])}:
|
||||||
|
return cand["name"] or "-"
|
||||||
|
return default_set["name"] or "-"
|
||||||
|
return "-"
|
||||||
|
except Exception:
|
||||||
|
return "-"
|
||||||
|
|
||||||
def switch_model_set(self, set_id):
|
def switch_model_set(self, set_id):
|
||||||
default_chain = moop.default_chain(None, "llm")
|
default_chain = moop.default_chain(None, "llm")
|
||||||
target = moop.get_set(None, set_id)
|
target = moop.get_set(None, set_id)
|
||||||
@ -59,6 +88,7 @@ class HendrikTUI:
|
|||||||
if not default_chain:
|
if not default_chain:
|
||||||
moop.set_default(None, "llm", set_id)
|
moop.set_default(None, "llm", set_id)
|
||||||
self.llm.set_chains({"llm": chain})
|
self.llm.set_chains({"llm": chain})
|
||||||
|
self.model_set_name = target.get("name") or self._lookup_model_set_name()
|
||||||
if self.current_session:
|
if self.current_session:
|
||||||
self.session_mgr.update_model_info(
|
self.session_mgr.update_model_info(
|
||||||
self.current_session.doc_id, self._model_info()
|
self.current_session.doc_id, self._model_info()
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import json
|
|||||||
from tools.coder import get_current_workspace
|
from tools.coder import get_current_workspace
|
||||||
|
|
||||||
from . import theme
|
from . import theme
|
||||||
|
from .actions import ACTIONS
|
||||||
from .menubar import draw_menubar, draw_menu_dropdown
|
from .menubar import draw_menubar, draw_menu_dropdown
|
||||||
|
|
||||||
# Alias warna agar kode drawing di bawah tetap ringkas.
|
# Alias warna agar kode drawing di bawah tetap ringkas.
|
||||||
@ -16,6 +17,7 @@ C_USER = theme.C_USER
|
|||||||
C_AI = theme.C_AI
|
C_AI = theme.C_AI
|
||||||
C_SYSTEM = theme.C_SYSTEM
|
C_SYSTEM = theme.C_SYSTEM
|
||||||
C_INPUT = theme.C_INPUT
|
C_INPUT = theme.C_INPUT
|
||||||
|
C_STATUS = theme.C_STATUS
|
||||||
C_STATUS_READY = theme.C_STATUS_READY
|
C_STATUS_READY = theme.C_STATUS_READY
|
||||||
C_STATUS_PROC = theme.C_STATUS_PROC
|
C_STATUS_PROC = theme.C_STATUS_PROC
|
||||||
C_ERROR = theme.C_ERROR
|
C_ERROR = theme.C_ERROR
|
||||||
@ -344,55 +346,66 @@ def draw_input(app, stdscr):
|
|||||||
|
|
||||||
|
|
||||||
def draw_status(app, stdscr):
|
def draw_status(app, stdscr):
|
||||||
# Status bar di baris h-9: mode, model, workspace, session
|
# Status bar di baris h-9.
|
||||||
|
# kiri : "STATUS nama_model_set nama_model workspace"
|
||||||
|
# kanan : "nama_character Ctrl+Return:Send"
|
||||||
|
# STATUS = mode READY/PROCESSING (berwarna). Bila terminal sempit, bagian
|
||||||
|
# workspace dipotong dari depan (sisa akhir path) agar sisi kanan utuh.
|
||||||
h, w = app.h, app.w
|
h, w = app.h, app.w
|
||||||
y = h - 9
|
y = h - 9
|
||||||
ws = get_current_workspace()
|
|
||||||
|
|
||||||
session_tag = ""
|
|
||||||
if app.current_session:
|
|
||||||
session_tag = f" {app.current_session.name} "
|
|
||||||
|
|
||||||
model = app.llm.model
|
|
||||||
mode = " PROCESSING " if app.processing else " READY "
|
mode = " PROCESSING " if app.processing else " READY "
|
||||||
|
set_name = (getattr(app, "model_set_name", "") or "-").strip() or "-"
|
||||||
|
model = (app.llm.model or "-").strip() or "-"
|
||||||
|
ws = get_current_workspace() or "-"
|
||||||
|
|
||||||
# Format: [MODE] model workspace session (menggunakan spasi sebagai pemisah)
|
send_key = ACTIONS["send_prompt"].get("shortcut") or "Ctrl+Return"
|
||||||
status_text = f"{mode} {model} {ws} {session_tag}"
|
right = f" {app.character_name} {send_key}:Send "
|
||||||
|
|
||||||
# Jika terlalu panjang, potong bagian workspace-nya saja agar tetap readable
|
# Sisi kiri hanya boleh memakai ruang selebar w - len(right) - 1 (pemisah).
|
||||||
|
avail = max(0, w - len(right) - 1)
|
||||||
|
fixed = len(mode) + len(set_name) + len(model) + 3 # 3 = spasi pemisah
|
||||||
ws_display = ws
|
ws_display = ws
|
||||||
if len(status_text) > w:
|
if fixed + len(ws_display) > avail:
|
||||||
max_ws_len = w - len(mode) - len(model) - len(session_tag) - 3
|
budget = max(0, avail - fixed)
|
||||||
if len(ws) > max_ws_len:
|
ws_display = (".." + ws)[-budget:] if budget > 0 else ""
|
||||||
ws_display = ".." + ws[-(max_ws_len - 2):]
|
|
||||||
status_text = f"{mode} {model} {ws_display} {session_tag}"
|
|
||||||
|
|
||||||
# Gambar background dasar
|
left = f"{mode} {set_name} {model} {ws_display}"[:avail]
|
||||||
full_status = status_text.ljust(w)[:w]
|
|
||||||
stdscr.addstr(y, 0, full_status, curses.color_pair(C_STATUS_INFO))
|
def _clip(text, x):
|
||||||
|
# Potong teks agar tidak melewati batas area kiri (kolom `avail`).
|
||||||
|
if x >= avail:
|
||||||
|
return ""
|
||||||
|
return text[: avail - x]
|
||||||
|
|
||||||
|
# Background penuh sepanjang baris
|
||||||
|
try:
|
||||||
|
stdscr.addstr(y, 0, " " * w, curses.color_pair(C_STATUS_INFO))
|
||||||
|
except curses.error:
|
||||||
|
pass
|
||||||
|
|
||||||
# Highlight mode dengan warna berbeda (Hijau/Kuning)
|
# Highlight mode dengan warna berbeda (Hijau/Kuning)
|
||||||
mode_attr = curses.color_pair(C_STATUS_READY) if not app.processing else curses.color_pair(C_STATUS_PROC)
|
mode_attr = curses.color_pair(C_STATUS_READY) if not app.processing else curses.color_pair(C_STATUS_PROC)
|
||||||
stdscr.addstr(y, 0, mode, mode_attr | curses.A_BOLD)
|
|
||||||
|
|
||||||
# Highlight Model, Workspace dan Session dengan warna Putih-Bold
|
|
||||||
highlight_attr = curses.color_pair(C_STATUS_INFO) | curses.A_BOLD
|
highlight_attr = curses.color_pair(C_STATUS_INFO) | curses.A_BOLD
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Mode sudah digambar, kita cari posisi setelah mode
|
stdscr.addstr(y, 0, left, highlight_attr)
|
||||||
model_start = len(mode) + 1 # melewati mode + 1 spasi
|
# Mode ditimpa lebih dulu dengan warnanya sendiri
|
||||||
ws_start = len(mode) + len(model) + 2
|
stdscr.addstr(y, 0, mode, mode_attr | curses.A_BOLD)
|
||||||
ws_len = len(ws_display)
|
# Posisi model set, model, dan workspace (mengikuti isi `left`)
|
||||||
|
set_start = len(mode) + 1
|
||||||
# Gambar Model
|
stdscr.addstr(y, set_start, _clip(set_name, set_start), highlight_attr)
|
||||||
stdscr.addstr(y, model_start, model, highlight_attr)
|
model_start = set_start + len(set_name) + 1
|
||||||
|
stdscr.addstr(y, model_start, _clip(model, model_start), highlight_attr)
|
||||||
# Gambar Workspace
|
ws_start = model_start + len(model) + 1
|
||||||
stdscr.addstr(y, ws_start, ws_display, highlight_attr)
|
if ws_display:
|
||||||
|
stdscr.addstr(y, ws_start, _clip(ws_display, ws_start), highlight_attr)
|
||||||
# Gambar Session
|
except curses.error:
|
||||||
session_start = ws_start + ws_len + 1 # melewati workspace + 1 spasi
|
pass
|
||||||
if session_tag:
|
|
||||||
stdscr.addstr(y, session_start, session_tag, highlight_attr)
|
# Sisi kanan: character + petunjuk tombol kirim
|
||||||
|
right_attr = curses.color_pair(C_STATUS) | curses.A_BOLD
|
||||||
|
try:
|
||||||
|
stdscr.addstr(y, w - len(right), right, right_attr)
|
||||||
except curses.error:
|
except curses.error:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -10,7 +10,7 @@ C_USER = 2 # user message: cyan
|
|||||||
C_AI = 3 # AI response: hijau
|
C_AI = 3 # AI response: hijau
|
||||||
C_SYSTEM = 4 # system log: kuning
|
C_SYSTEM = 4 # system log: kuning
|
||||||
C_INPUT = 5 # text input: putih
|
C_INPUT = 5 # text input: putih
|
||||||
C_STATUS = 6 # status bar: hitam di atas kuning
|
C_STATUS = 6 # status bar: hitam di atas biru
|
||||||
C_STATUS_READY = 10 # status READY: hijau
|
C_STATUS_READY = 10 # status READY: hijau
|
||||||
C_STATUS_PROC = 11 # status PROCESSING: kuning
|
C_STATUS_PROC = 11 # status PROCESSING: kuning
|
||||||
C_SEP = 7 # separator line: magenta
|
C_SEP = 7 # separator line: magenta
|
||||||
@ -38,7 +38,7 @@ def init_colors():
|
|||||||
curses.init_pair(C_AI, curses.COLOR_GREEN, -1)
|
curses.init_pair(C_AI, curses.COLOR_GREEN, -1)
|
||||||
curses.init_pair(C_SYSTEM, curses.COLOR_YELLOW, -1)
|
curses.init_pair(C_SYSTEM, curses.COLOR_YELLOW, -1)
|
||||||
curses.init_pair(C_INPUT, curses.COLOR_WHITE, -1)
|
curses.init_pair(C_INPUT, curses.COLOR_WHITE, -1)
|
||||||
curses.init_pair(C_STATUS, curses.COLOR_BLACK, curses.COLOR_YELLOW)
|
curses.init_pair(C_STATUS, curses.COLOR_BLACK, curses.COLOR_BLUE)
|
||||||
curses.init_pair(C_STATUS_READY, curses.COLOR_BLACK, curses.COLOR_GREEN + 8)
|
curses.init_pair(C_STATUS_READY, curses.COLOR_BLACK, curses.COLOR_GREEN + 8)
|
||||||
curses.init_pair(C_STATUS_PROC, curses.COLOR_BLACK, curses.COLOR_YELLOW)
|
curses.init_pair(C_STATUS_PROC, curses.COLOR_BLACK, curses.COLOR_YELLOW)
|
||||||
curses.init_pair(C_STATUS_INFO, curses.COLOR_BLACK, curses.COLOR_WHITE)
|
curses.init_pair(C_STATUS_INFO, curses.COLOR_BLACK, curses.COLOR_WHITE)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user