hendrik/interfaces/tui/actions.py

166 lines
4.6 KiB
Python

# actions.py — Registry aksi TUI (single source of truth).
#
# Semua aksi didefinisikan satu kali di sini, lengkap dengan:
# * shortcut key langsung (dipakai oleh dispatch global)
# * spesifikasi item menu (dipakai oleh menubar)
# * handler & predikat enabled
# Dengan begitu shortcut dan menu selalu sinkron; developer cukup
# menambah/edit satu entri untuk fitur baru.
from .keycodes import (
KEY_CTRL_C,
KEY_CTRL_ENTER,
KEY_CTRL_N,
KEY_CTRL_O,
KEY_ESC,
KEY_F2,
KEY_F4,
KEY_F6,
)
from .input import (
new_session_popup,
session_browser_popup,
rename_popup,
workspace_popup,
)
from .moopui import (
model_selector_popup,
sets_manage_popup,
providers_manage_popup,
)
from .agent import submit, log
# ---------------------------------------------------------------- handlers ---
def _exit_app(app, stdscr):
app.running = False
def _cancel_inference(app, stdscr):
app.llm.cancel_requested = True
app.agent_done.set()
log(app, "system", " Inference cancelled by user")
def _send_prompt(app, stdscr):
submit(app, stdscr)
def _ready(app):
return not app.processing
# ------------------------------------------------------------- action spec ---
# Tiap aksi: key, label, mnemonic, shortcut (teks), handler, enabled.
ACTIONS = {
"new_session": {
"key": KEY_CTRL_N,
"label": "New Session", "mnemonic": "N", "shortcut": "Ctrl+N",
"handler": new_session_popup, "enabled": _ready,
},
"open_session": {
"key": KEY_CTRL_O,
"label": "Open Session", "mnemonic": "O", "shortcut": "Ctrl+O",
"handler": session_browser_popup, "enabled": _ready,
},
"rename_session": {
"key": KEY_F2,
"label": "Rename Session", "mnemonic": "R", "shortcut": "F2",
"handler": rename_popup,
"enabled": lambda app: _ready(app) and app.current_session is not None,
},
"exit_app": {
"key": KEY_CTRL_C,
"label": "Exit", "mnemonic": "E", "shortcut": "Ctrl+C",
"handler": _exit_app, "enabled": lambda app: True,
},
"send_prompt": {
"key": KEY_CTRL_ENTER,
"label": "Send Prompt", "mnemonic": "P", "shortcut": "Ctrl+Enter",
"handler": _send_prompt, "enabled": _ready,
},
"cancel_inference": {
"key": KEY_ESC,
"label": "Cancel Inference", "mnemonic": "C", "shortcut": "Esc",
"handler": _cancel_inference, "enabled": lambda app: app.processing,
},
"select_model": {
"key": KEY_F4,
"label": "Select Model", "mnemonic": "S", "shortcut": "F4",
"handler": model_selector_popup, "enabled": _ready,
},
"manage_sets": {
"key": None,
"label": "Manage Sets", "mnemonic": "S", "shortcut": "",
"handler": sets_manage_popup, "enabled": _ready,
},
"manage_providers": {
"key": None,
"label": "Manage Providers", "mnemonic": "P", "shortcut": "",
"handler": providers_manage_popup, "enabled": _ready,
},
"change_workspace": {
"key": KEY_F6,
"label": "Change Workspace", "mnemonic": "C", "shortcut": "F6",
"handler": workspace_popup, "enabled": _ready,
},
}
# ---------------------------------------------------------------- menu bar ---
def _item(action_id: str) -> dict:
item = dict(ACTIONS[action_id])
item["id"] = action_id
return item
# Struktur menu bar. Urutan & mnemonic sesuai spesifikasi:
# Alt+S → [S]ession, Alt+A → [A]gent, Alt+M → [M]odel, Alt+W → [W]orkspace
MENUS = [
{
"name": "Session",
"mnemonic": "S",
"items": [
_item("new_session"),
_item("open_session"),
_item("rename_session"),
"sep",
_item("exit_app"),
],
},
{
"name": "Agent",
"mnemonic": "A",
"items": [
_item("send_prompt"),
_item("cancel_inference"),
],
},
{
"name": "Model",
"mnemonic": "M",
"items": [
_item("select_model"),
"sep",
_item("manage_sets"),
_item("manage_providers"),
],
},
{
"name": "Workspace",
"mnemonic": "W",
"items": [
_item("change_workspace"),
],
},
]
# ------------------------------------------------------------------ execute ---
def perform(app, stdscr, action_id: str):
# Jalankan aksi; abaikan jika disabled (mis. aksi READY-only saat processing).
spec = ACTIONS.get(action_id)
if not spec or not spec["enabled"](app):
return
spec["handler"](app, stdscr)