본문으로 건너뛰기

CLI 확장

Hermes는 HermesCLI에 보호된 확장 후크를 노출하므로 래퍼 CLI는 1000개 이상의 라인 run() 메서드를 재정의하지 않고도 위젯, 키 바인딩 및 레이아웃 사용자 정의를 추가할 수 있습니다. 이렇게 하면 확장 기능이 내부 변경 사항으로부터 분리된 상태로 유지됩니다.

확장점

5개의 확장 솔기를 사용할 수 있습니다.

후크목적다음 경우에 재정의하세요...
_get_extra_tui_widgets()레이아웃에 위젯 삽입지속적인 UI 요소(패널, 상태 표시줄, 미니 플레이어)가 필요합니다.
_register_extra_tui_keybindings(kb, *, input_area)키보드 단축키 추가단축키가 필요합니다(토글 패널, 전송 컨트롤, 모달 단축키)
_build_tui_layout_children(**widgets)위젯 순서에 대한 전체 제어기존 위젯을 재정렬하거나 래핑해야 합니다(드물게).
process_command()사용자 정의 슬래시 명령 추가/mycommand 처리가 필요합니다(기존 후크).
_build_tui_style_dict()사용자 정의 프롬프트_툴킷 스타일맞춤 색상이나 스타일이 필요합니다(기존 후크).

처음 세 개는 새로운 보호 후크입니다. 마지막 두 개는 이미 존재했습니다.

빠른 시작: 래퍼 CLI

#!/usr/bin/env python3
"""my_cli.py — Example wrapper CLI that extends Hermes."""

from cli import HermesCLI
from prompt_toolkit.layout import FormattedTextControl, Window
from prompt_toolkit.filters import Condition


class MyCLI(HermesCLI):

def __init__(self, **kwargs):
super().__init__(**kwargs)
self._panel_visible = False

def _get_extra_tui_widgets(self):
"""Add a toggleable info panel above the status bar."""
cli_ref = self
return [
Window(
FormattedTextControl(lambda: "📊 My custom panel content"),
height=1,
filter=Condition(lambda: cli_ref._panel_visible),
),
]

def _register_extra_tui_keybindings(self, kb, *, input_area):
"""F2 toggles the custom panel."""
cli_ref = self

@kb.add("f2")
def _toggle_panel(event):
cli_ref._panel_visible = not cli_ref._panel_visible

def process_command(self, cmd: str) -> bool:
"""Add a /panel slash command."""
if cmd.strip().lower() == "/panel":
self._panel_visible = not self._panel_visible
state = "visible" if self._panel_visible else "hidden"
print(f"Panel is now {state}")
return True
return super().process_command(cmd)


if __name__ == "__main__":
cli = MyCLI()
cli.run()

실행하세요:

cd ~/.hermes/hermes-agent
source.venv/bin/activate
python my_cli.py

후크 참조

_get_extra_tui_widgets()

TUI 레이아웃에 삽입할 Prompt_toolkit 위젯 목록을 반환합니다. 위젯은 스페이서와 상태 표시줄 사이에 표시됩니다(입력 영역 위, 기본 출력 아래).

def _get_extra_tui_widgets(self) -> list:
return # default: no extra widgets

각 위젯은 Prompt_toolkit 컨테이너여야 합니다(예: Window, ConditionalContainer, HSplit). 위젯을 전환 가능하게 만들려면 ConditionalContainer 또는 filter=Condition(...)을 사용하세요.

from prompt_toolkit.layout import ConditionalContainer, Window, FormattedTextControl
from prompt_toolkit.filters import Condition

def _get_extra_tui_widgets(self):
return [
ConditionalContainer(
Window(FormattedTextControl("Status: connected"), height=1),
filter=Condition(lambda: self._show_status),
),
]

_register_extra_tui_keybindings(kb, *, input_area)

Hermes가 자체 키 바인딩을 등록한 후 레이아웃이 빌드되기 전에 호출됩니다. kb에 키 바인딩을 추가하세요.

def _register_extra_tui_keybindings(self, kb, *, input_area):
pass # default: no extra keybindings

매개변수:

  • kb — Prompt_toolkit 애플리케이션용 KeyBindings 인스턴스
  • input_area — 사용자 입력을 읽거나 조작해야 하는 경우 기본 TextArea 위젯
def _register_extra_tui_keybindings(self, kb, *, input_area):
cli_ref = self

@kb.add("f3")
def _clear_input(event):
input_area.text = ""

@kb.add("f4")
def _insert_template(event):
input_area.text = "/search "

내장된 키 바인딩으로 충돌 방지: Enter(제출), Escape Enter(줄바꿈), Ctrl-C(중단), Ctrl-D(종료), Tab (자동 제안 수락). 기능 키 F2+와 Ctrl 조합은 일반적으로 안전합니다.

_build_tui_layout_children(**widgets)

위젯 순서를 완전히 제어해야 하는 경우에만 이를 재정의하세요. 대부분의 확장 프로그램은 대신 _get_extra_tui_widgets()을 사용해야 합니다.

def _build_tui_layout_children(self, *, sudo_widget, secret_widget,
approval_widget, clarify_widget, model_picker_widget=None,
spinner_widget=None, spacer, status_bar, input_rule_top,
image_bar, input_area, input_rule_bot, voice_status_bar,
completions_menu) -> list:

기본 구현은 다음을 반환합니다(모든 None 위젯은 필터링됩니다).

[
Window(height=0), # anchor
sudo_widget, # sudo password prompt (conditional)
secret_widget, # secret input prompt (conditional)
approval_widget, # dangerous command approval (conditional)
clarify_widget, # clarify question UI (conditional)
model_picker_widget, # model picker overlay (conditional)
spinner_widget, # thinking spinner (conditional)
spacer, # fills remaining vertical space
*self._get_extra_tui_widgets(), # YOUR WIDGETS GO HERE
status_bar, # model/token/context status line
input_rule_top, # ─── border above input
image_bar, # attached images indicator
input_area, # user text input
input_rule_bot, # ─── border below input
voice_status_bar, # voice mode status (conditional)
completions_menu, # autocomplete dropdown
]

레이아웃 다이어그램

위에서 아래로 기본 레이아웃:

  1. 출력 영역 — 대화 기록 스크롤
  2. 스페이서
  3. 추가 위젯_get_extra_tui_widgets()에서
  4. 상태 표시줄 — 모델, 컨텍스트 %, 경과 시간
  5. 이미지 표시줄 — 첨부된 이미지 수
  6. 입력 영역 — 사용자 프롬프트
  7. 음성 상태 — 녹음 표시
  8. 완성 메뉴 — 자동 완성 제안

  • 상태 변경 후 디스플레이 무효화: self._invalidate()을 호출하여 프롬프트_툴킷 다시 그리기를 트리거합니다.
  • 액세스 에이전트 상태: self.agent, self.model, self.conversation_history를 모두 사용할 수 있습니다.
  • 사용자 정의 스타일: _build_tui_style_dict()을 재정의하고 사용자 정의 스타일 클래스에 대한 항목을 추가합니다.
  • 슬래시 명령: process_command()을 override하고, 명령을 처리하고, 다른 모든 것에 대해 super().process_command(cmd)을 호출합니다.
  • **꼭 필요한 경우가 아니면 run()**을 재정의하지 마세요. 확장 후크는 이러한 결합을 방지하기 위해 특별히 존재합니다.