"""Agent input panel — entry, action buttons, model/language dropdowns.""" import logging import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk, GObject from cht.agent.runner import ACTIONS from cht.transcriber.engine import LANGUAGES log = logging.getLogger(__name__) class AgentInputPanel(Gtk.Frame): """Input bar with action buttons, model/lang selectors, and text entry.""" __gsignals__ = { "send-requested": (GObject.SignalFlags.RUN_FIRST, None, (str,)), "action-requested": (GObject.SignalFlags.RUN_FIRST, None, (str,)), "model-changed": (GObject.SignalFlags.RUN_FIRST, None, (str,)), "lang-changed": (GObject.SignalFlags.RUN_FIRST, None, (str,)), "history-toggled": (GObject.SignalFlags.RUN_FIRST, None, (bool,)), "permission-changed": (GObject.SignalFlags.RUN_FIRST, None, (str,)), } def __init__(self, **kwargs): super().__init__(**kwargs) outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4) outer.set_margin_start(4) outer.set_margin_end(4) outer.set_margin_top(4) outer.set_margin_bottom(4) actions_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=4) for label, verb in ACTIONS.items(): btn = Gtk.Button(label=label) btn.add_css_class("flat") btn.connect("clicked", lambda b, v=verb: self.emit("action-requested", v)) actions_box.append(btn) spacer = Gtk.Box() spacer.set_hexpand(True) actions_box.append(spacer) model_label = Gtk.Label(label="Model:") model_label.add_css_class("dim-label") actions_box.append(model_label) self._model_dropdown = Gtk.DropDown.new_from_strings([]) self._model_dropdown.set_size_request(200, -1) self._model_dropdown.connect("notify::selected", self._on_model_changed) actions_box.append(self._model_dropdown) lang_label = Gtk.Label(label="Lang:") lang_label.add_css_class("dim-label") actions_box.append(lang_label) lang_names = list(LANGUAGES.keys()) self._lang_names = lang_names self._lang_dropdown = Gtk.DropDown.new_from_strings(lang_names) self._lang_dropdown.set_selected(0) self._lang_dropdown.connect("notify::selected", self._on_lang_changed) actions_box.append(self._lang_dropdown) history_toggle = Gtk.CheckButton(label="Chat") history_toggle.set_tooltip_text("Include conversation history in prompts") history_toggle.connect("toggled", lambda b: self.emit("history-toggled", b.get_active())) actions_box.append(history_toggle) perm_label = Gtk.Label(label="Perms:") perm_label.add_css_class("dim-label") actions_box.append(perm_label) self._perm_modes = ["default", "acceptEdits", "bypassPermissions", "dontAsk", "plan"] self._perm_labels = ["Default", "Accept Edits", "Bypass All", "Don't Ask", "Plan Only"] self._perm_dropdown = Gtk.DropDown.new_from_strings(self._perm_labels) self._perm_dropdown.set_size_request(140, -1) self._perm_dropdown.set_tooltip_text("Claude SDK permission mode") self._perm_dropdown.connect("notify::selected", self._on_perm_changed) actions_box.append(self._perm_dropdown) outer.append(actions_box) input_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=4) self._entry = Gtk.Entry() self._entry.set_hexpand(True) self._entry.set_placeholder_text("Message agent... (@F1-3 frames, @T1-5 transcript)") self._entry.connect("activate", lambda e: self._do_send()) input_row.append(self._entry) send_btn = Gtk.Button(label="Send") send_btn.add_css_class("suggested-action") send_btn.connect("clicked", lambda b: self._do_send()) input_row.append(send_btn) outer.append(input_row) self.set_child(outer) @property def entry(self) -> Gtk.Entry: """The text entry widget (for focus checks).""" return self._entry def get_text(self) -> str: return self._entry.get_text().strip() def clear_text(self) -> None: self._entry.set_text("") def populate_models(self, models: list[str], current: str | None = None) -> None: if not models: return string_list = Gtk.StringList.new(models) self._model_dropdown.set_model(string_list) if current: for i, m in enumerate(models): if m == current: self._model_dropdown.set_selected(i) break def _do_send(self): text = self.get_text() self.clear_text() self.emit("send-requested", text) def _on_model_changed(self, dropdown, _pspec): idx = dropdown.get_selected() model = dropdown.get_model() if model and idx < model.get_n_items(): self.emit("model-changed", model.get_string(idx)) def _on_lang_changed(self, dropdown, _pspec): idx = dropdown.get_selected() if idx < len(self._lang_names): lang_code = LANGUAGES[self._lang_names[idx]] self.emit("lang-changed", lang_code or "") def _on_perm_changed(self, dropdown, _pspec): idx = dropdown.get_selected() if idx < len(self._perm_modes): self.emit("permission-changed", self._perm_modes[idx]) def set_permission_mode(self, mode: str) -> None: try: idx = self._perm_modes.index(mode) self._perm_dropdown.set_selected(idx) except ValueError: pass