扩展 CLI
Hermes 在 HermesCLI 上公开受保护的扩展挂钩,因此包装器 CLI 可以添加小部件、键绑定和布局自定义,而无需覆盖 1000 多行 run() 方法。这可以使您的扩展与内部更改脱钩。
扩展点
有五种延伸接缝可供选择:
| 钩 | 目的 | 当...时覆盖 |
|---|---|---|
_get_extra_tui_widgets() | _get_extra_tui_widgets()将小部件注入布局 | 您需要一个持久的 UI 元素(面板、状态行、迷你播放器) |
_register_extra_tui_keybindings(kb, *, input_area) | _register_extra_tui_keybindings(kb, *, input_area)添加键盘快捷键 | 您需要热键(切换面板、传输控件、模式快捷键) |
_build_tui_layout_children(**widgets) | _build_tui_layout_children(**widgets)完全控制小部件排序 | 您需要重新排序或包装现有的小部件(罕见) |
process_command() | process_command()添加自定义斜杠命令 | 您需要 /mycommand 处理(预先存在的钩子) |
_build_tui_style_dict() | _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 布局中的提示工具包小部件列表。小部件出现在间隔符和状态栏之间 - 在输入区域上方但在主输出下方。
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, spinner_widget, spacer,
status_bar, input_rule_top, image_bar, input_area,
input_rule_bot, voice_status_bar, completions_menu) -> list:
默认实现返回:
[
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)
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()触发prompt_toolkit重绘。 - 访问代理状态:
self.agent、self.model、self.conversation_history均可用。 - 自定义样式:覆盖
_build_tui_style_dict()并添加自定义样式类的条目。 - 斜线命令:覆盖
process_command(),处理您的命令,并为其他所有内容调用super().process_command(cmd)。 - 除非绝对必要,否则不要覆盖
run()— 扩展钩子的存在是为了避免这种耦合。