sidebar_position: 9 title: "Tools Runtime" description: "Runtime behavior of the tool registry, toolsets, dispatch, and terminal environments" lang: ru


Инструменты

Инструменты Hermes представляют собой саморегистрирующиеся функции, сгруппированные в наборы инструментов и выполняемые через центральную систему регистрации/диспетчеризации.

Первичные файлы:

Модель регистрации инструмента

Каждый инструментальный модуль вызывает registry.register(...) во время импорта.

model_tools.py отвечает за импорт/обнаружение инструментальных модулей и создание списка схем, используемых моделью.

Как работает registry.register()

Каждый файл инструмента в tools/ вызывает registry.register() на уровне модуля, чтобы объявить о себе. Сигнатура функции:

registry.register(
    name="terminal",               # Unique tool name (used in API schemas)
    toolset="terminal",            # Toolset this tool belongs to
    schema={...},                  # OpenAI function-calling schema (description, parameters)
    handler=handle_terminal,       # The function that executes when the tool is called
    check_fn=check_terminal,       # Optional: returns True/False for availability
    requires_env=["SOME_VAR"],     # Optional: env vars needed (for UI display)
    is_async=False,                # Whether the handler is an async coroutine
    description="Run commands",    # Human-readable description
    emoji="💻",                    # Emoji for spinner/progress display
)

Каждый вызов создает ToolEntry, хранящийся в одноэлементном словаре ToolRegistry._tools с ключом по имени инструмента. Если конфликт имен происходит между наборами инструментов, регистрируется предупреждение, и более поздняя регистрация выигрывает.

Открытие: discover_builtin_tools()

При импорте model_tools.py он вызывает discover_builtin_tools() из tools/registry.py. Эта функция сканирует каждый файл tools/*.py, используя анализ AST, чтобы найти модули, содержащие вызовы registry.register() верхнего уровня, а затем импортирует их:

# tools/registry.py (simplified)
def discover_builtin_tools(tools_dir=None):
    tools_path = Path(tools_dir) if tools_dir else Path(__file__).parent
    for path in sorted(tools_path.glob("*.py")):
        if path.name in {"__init__.py", "registry.py", "mcp_tool.py"}:
            continue
        if _module_registers_tools(path):  # AST check for top-level registry.register()
            importlib.import_module(f"tools.{path.stem}")

Это автоматическое обнаружение означает, что новые файлы инструментов подбираются автоматически — не нужно составлять список вручную. Проверка AST соответствует только вызовам registry.register() верхнего уровня (не вызовам внутри функций), поэтому вспомогательные модули в tools/ не импортируются.

Каждый импорт запускает вызовы registry.register() модуля. Ошибки в дополнительных инструментах (например, отсутствие fal_client для создания изображения) фиксируются и протоколируются — они не мешают загрузке других инструментов.

После обнаружения основного инструмента также обнаруживаются инструменты MCP и плагины:

  1. Инструменты MCPtools.mcp_tool.discover_mcp_tools() считывает конфигурацию сервера MCP и регистрирует инструменты с внешних серверов.
  2. Инструменты плагиновhermes_cli.plugins.discover_plugins() загружает плагины пользователя/проекта/pip, которые могут регистрировать дополнительные инструменты.

Проверка доступности инструмента (check_fn)

Каждый инструмент может дополнительно предоставить check_fn — вызываемый объект, который возвращает True, когда инструмент доступен, и False в противном случае. Типичные проверки включают в себя:

Когда registry.get_definitions() создает список схем для модели, он запускает check_fn() каждого инструмента:

# Simplified from registry.py
if entry.check_fn:
    try:
        available = bool(entry.check_fn())
    except Exception:
        available = False   # Exceptions = unavailable
    if not available:
        continue            # Skip this tool entirely

Ключевые модели поведения: - Результаты проверки кэшируются для каждого вызова — если несколько инструментов используют один и тот же check_fn, он запускается только один раз. - Исключения в check_fn() рассматриваются как «недоступные» (отказоустойчивые). - Метод is_toolset_available() проверяет, проходит ли набор инструментов check_fn, используемый для отображения пользовательского интерфейса и разрешения набора инструментов.

Разрешение набора инструментов

Наборы инструментов — это именованные пакеты инструментов. Гермес решает их посредством:

Как get_tool_definitions() фильтрует инструменты

Основная точка входа — model_tools.get_tool_definitions(enabled_toolsets, disabled_toolsets, quiet_mode):

  1. Если указан enabled_toolsets — включены только инструменты из этих наборов инструментов. Имя каждого набора инструментов разрешается с помощью resolve_toolset(), который расширяет составные наборы инструментов до отдельных имен инструментов.

  2. Если указан disabled_toolsets — начните со ВСЕХ наборов инструментов, затем вычтите отключенные.

  3. Если ни то, ни другое — включите все известные наборы инструментов.

  4. Фильтрация реестра — разрешенный набор имен инструментов передается registry.get_definitions(), который применяет фильтрацию check_fn и возвращает схемы в формате OpenAI.

  5. Динамическое исправление схемы — после фильтрации схемы execute_code и browser_navigate динамически настраиваются так, чтобы ссылаться только на инструменты, которые фактически прошли фильтрацию (предотвращает галлюцинацию модели о недоступных инструментах).

Названия устаревших наборов инструментов

Имена старых наборов инструментов с суффиксами _tools (например, web_tools, terminal_tools) сопоставляются с современными именами инструментов через _LEGACY_TOOLSET_MAP для обеспечения обратной совместимости.

Отправка

Во время выполнения инструменты передаются через центральный реестр с исключениями цикла агента для некоторых инструментов уровня агента, таких как обработка памяти/задач/поиска сеанса.

Поток отправки: модельtool_call → выполнение обработчика

Когда модель возвращает tool_call, порядок действий следующий:

Model response with tool_call
    
run_agent.py agent loop
    
model_tools.handle_function_call(name, args, task_id, user_task)
    
[Agent-loop tools?]  handled directly by agent loop (todo, memory, session_search, delegate_task)
    
[Plugin pre-hook]  invoke_hook("pre_tool_call", ...)
    
registry.dispatch(name, args, **kwargs)
    
Look up ToolEntry by name
    
[Async handler?]  bridge via _run_async()
[Sync handler?]   call directly
    
Return result string (or JSON error)
    
[Plugin post-hook]  invoke_hook("post_tool_call", ...)

Ошибка переноса

Все выполнение инструмента связано с обработкой ошибок на двух уровнях:

  1. registry.dispatch() — перехватывает любое исключение из обработчика и возвращает {"error": "Tool execution failed: ExceptionType: message"} в формате JSON.

  2. handle_function_call() — переносит всю отправку во вторичную попытку, за исключением того, что возвращается {"error": "Error executing tool_name: message"}.

Это гарантирует, что модель всегда получит правильно сформированную строку JSON, а не необработанное исключение.

Инструменты цикла агента

Перед отправкой реестра перехватываются четыре инструмента, поскольку им требуется состояние уровня агента (TodoStore, MemoryStore и т. д.):

Схемы этих инструментов все еще зарегистрированы в реестре (для get_tool_definitions), но их обработчики возвращают ошибку-заглушку, если диспетчеризация каким-то образом достигает их напрямую.

Асинхронный мост

Когда обработчик инструмента является асинхронным, _run_async() соединяет его с путем синхронизации:

Порядок утверждения DANGEROUS_PATTERNS

В терминальном инструменте интегрирована система одобрения опасных команд, определенная в tools/approval.py:

  1. Обнаружение шаблоновDANGEROUS_PATTERNS — это список кортежей (regex, description), охватывающих деструктивные операции:
  2. Рекурсивное удаление (rm -rf)
  3. Форматирование файловой системы (mkfs, dd)
  4. Деструктивные операции SQL (DROP TABLE, DELETE FROM без WHERE)
  5. Конфигурация системы перезаписывается (> /etc/)
  6. Сервисные манипуляции (systemctl stop)
  7. Удаленное выполнение кода (curl | sh)
  8. Вилочные бомбы, технологические убийства и т. д.

  9. Обнаружение — перед выполнением любой команды терминала detect_dangerous_command(command) проверяет все шаблоны.

  10. Запрос на одобрение — если совпадение найдено:

  11. Режим CLI — интерактивный запрос предлагает пользователю одобрить, отклонить или разрешить навсегда.
  12. Режим шлюза — обратный вызов асинхронного утверждения отправляет запрос на платформу обмена сообщениями.
  13. Интеллектуальное утверждение — дополнительно вспомогательный модуль LLM может автоматически утверждать команды с низким уровнем риска, соответствующие шаблонам (например, rm -rf node_modules/ безопасно, но соответствует «рекурсивному удалению»).

  14. Состояние сеанса — утверждения отслеживаются для каждого сеанса. После того как вы разрешите «рекурсивное удаление» сеанса, последующие команды rm -rf не будут выдавать повторные запросы.

  15. Постоянный список разрешенных — опция «разрешить навсегда» записывает шаблон в command_allowlist config.yaml, сохраняя его на протяжении всех сеансов.

Терминал/среда выполнения

Терминальная система поддерживает несколько бэкэндов:

Он также поддерживает:

Параллелизм

Вызовы инструментов могут выполняться последовательно или одновременно в зависимости от набора инструментов и требований к взаимодействию.

Связанные документы