H繁中版
文件開發者指南extending the cli
<!-- Source: https://hermesbible.com/docs/developer-guide/extending-the-cli -->

Hermes 在 HermesCLI 上暴露受保護的擴充 hook,讓包裝 CLI 可以新增小工具、鍵綁定和版面自訂,而無需覆寫 1000 多行的 run() 方法。這使你的擴充與內部變更解耦。

擴充點

有五個可用的擴充接縫:

Hook用途何時覆寫…
_get_extra_tui_widgets()將小工具注入到版面中你需要持久的 UI 元素(面板、狀態列、迷你播放器)
_register_extra_tui_keybindings(kb, *, input_area)新增鍵盤快捷鍵你需要熱鍵(切換面板、傳輸控制、模態快捷鍵)
_build_tui_layout_children(**widgets)完全控制小工具排序你需要重新排序或包裝現有小工具(少見)
process_command()新增自訂斜線命令你需要 /mycommand 處理(已存在的 hook)
_build_tui_style_dict()自訂 prompt_toolkit 樣式你需要自訂顏色或樣式(已存在的 hook)

前三個是新的受保護 hook。後兩個已存在。

快速開始:包裝 CLI

#!/usr/bin/env python3
"""my_cli.py — 擴展 Hermes 的範例包裝 CLI。"""

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):
        """在狀態列上方新增一個可切換的資訊面板。"""
        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 切換自訂面板。"""
        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:
        """新增 /panel 斜線命令。"""
        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

Hook 參考

_get_extra_tui_widgets()

回傳要插入 TUI 版面的 prompt_toolkit 小工具列表。小工具出現在間距和狀態列之間——在輸入區域上方但主要輸出下方。

def _get_extra_tui_widgets(self) -> list:
    return []  # 預設:無額外小工具

每個小工具應是一個 prompt_toolkit 容器(例如 WindowConditionalContainerHSplit)。使用 ConditionalContainerfilter=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  # 預設:無額外鍵綁定

參數:

  • 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),       # 錨點
    sudo_widget,            # sudo 密碼提示(條件式)
    secret_widget,          # 密鑰輸入提示(條件式)
    approval_widget,        # 危險命令審核(條件式)
    clarify_widget,         # clarify 問題 UI(條件式)
    model_picker_widget,    # 模型選擇器覆蓋(條件式)
    spinner_widget,         # 思考旋轉器(條件式)
    spacer,                 # 填充剩餘垂直空間
    *self._get_extra_tui_widgets(),  # 你的小工具在這裡
    status_bar,             # 模型/token/上下文狀態列
    input_rule_top,         # ─── 輸入上方邊界
    image_bar,              # 附加圖片指示器
    input_area,             # 使用者文字輸入
    input_rule_bot,         # ─── 輸入下方邊界
    voice_status_bar,       # 語音模式狀態(條件式)
    completions_menu,       # 自動完成下拉選單
]

版面圖

預設版面從上到下:

  1. 輸出區域 — 捲動的對話歷史
  2. 間距
  3. 額外小工具 — 來自 _get_extra_tui_widgets()
  4. 狀態列 — 模型、上下文 %、已用時間
  5. 圖片列 — 附加圖片計數
  6. 輸入區域 — 使用者提示
  7. 語音狀態 — 錄音指示器
  8. 自動完成選單 — 自動完成建議

提示

  • 狀態變更後使顯示失效:呼叫 self._invalidate() 以觸發 prompt_toolkit 重繪。
  • 存取 Agent 狀態self.agentself.modelself.conversation_history 都可用。
  • 自訂樣式:覆寫 _build_tui_style_dict() 並為你的自訂樣式類別新增項目。
  • 斜線命令:覆寫 process_command(),處理你的命令,並為其他所有呼叫 super().process_command(cmd)
  • 不要覆寫 run() 除非絕對必要——擴充 hook 就是為了避免那種耦合而存在的。


ACP 內部