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
]
레이아웃 다이어그램
위에서 아래로 기본 레이아웃:
- 출력 영역 — 대화 기록 스크롤
- 스페이서
- 추가 위젯 —
_get_extra_tui_widgets()에서 - 상태 표시줄 — 모델, 컨텍스트 %, 경과 시간
- 이미지 표시줄 — 첨부된 이미지 수
- 입력 영역 — 사용자 프롬프트
- 음성 상태 — 녹음 표시
- 완성 메뉴 — 자동 완성 제안
팁
- 상태 변경 후 디스플레이 무효화:
self._invalidate()을 호출하여 프롬프트_툴킷 다시 그리기를 트리거합니다. - 액세스 에이전트 상태:
self.agent,self.model,self.conversation_history를 모두 사용할 수 있습니다. - 사용자 정의 스타일:
_build_tui_style_dict()을 재정의하고 사용자 정의 스타일 클래스에 대한 항목을 추가합니다. - 슬래시 명령:
process_command()을 override하고, 명령을 처리하고, 다른 모든 것에 대해super().process_command(cmd)을 호출합니다. - **꼭 필요한 경우가 아니면
run()**을 재정의하지 마세요. 확장 후크는 이러한 결합을 방지하기 위해 특별히 존재합니다.