Постоянные цели (Goals)

Постоянные цели (Goals)

Постоянные цели (Persistent Goals) — механизм Hermes Agent для автономной работы над задачей. /goal задаёт стоячую цель, которая сохраняется между ходами агента. После каждого хода лёгкая судейская модель (judge) проверяет, достигнута ли цель. Если нет — Hermes автоматически подаёт себе продолжение и делает следующий шаг, пока цель не будет достигнута, приостановлена или не исчерпается бюджет ходов.

Это реализация паттерна Ralph loop, вдохновлённая Codex CLI 0.128.0 (Eric Traut, OpenAI). Ключевая идея — держать цель активной между ходами и не останавливаться, пока она не выполнена — принадлежит Codex. Реализация в Hermes самостоятельна и адаптирована к собственной архитектуре.

Когда использовать

  • «Исправь все ошибки линтера в src/ и проверь, что ruff check проходит»
  • «Портируй функцию X из репозитория Y с тестами и добейся зелёного CI»
  • «Расследуй, почему session ID иногда дрейфуют при сжатии контекста, и напиши отчёт»
  • «Построй CLI для переименования фото по EXIF-датам и протестируй на папке photos/»

Задачи, где агент делает один ход и останавливается, не нуждаются в /goal. Задачи, где вам пришлось бы сказать «продолжай» три раза — идеальный сценарий.

Быстрый старт

/goal Исправь все падающие тесты в tests/hermes_cli/ и убедись, что scripts/run_tests.sh проходит для этой директории

Что вы увидите:

  1. Цель принята⊙ Goal set (20-turn budget): <ваша цель>
  2. Ход 1 — Hermes начинает работать, как если бы вы отправили цель как обычное сообщение.
  3. Судья оценивает — после хода судейская модель решает: done или continue.
  4. Цикл продолжается — если continue: ↻ Continuing toward goal (1/20): <причина судьи>
  5. Завершение✓ Goal achieved: <причина> или ⏸ Goal paused — N/20 turns used

Команды

Команда Описание
/goal <текст> Установить (или заменить) цель. Сразу запускает первый ход.
/goal draft <текст> Сгенерировать контракт выполнения из цели на естественном языке и установить его (см. «Контракты выполнения»).
/goal show Показать активный контракт выполнения.
/goal или /goal status Текущая цель, статус и использованные ходы.
/goal pause Приостановить цикл без сброса цели.
/goal resume Возобновить цикл (счётчик ходов сбрасывается).
/goal clear Удалить цель полностью.
/goal wait <pid> [причина] Припарковать цикл до завершения фонового процесса (см. «Парковка на фоновые процессы»).
/goal unwait Снять парковку и возобновить цикл немедленно.

Команды работают идентично в CLI и на всех платформах шлюза (Telegram, Discord, Slack, Matrix, Signal, WhatsApp, SMS, iMessage, Webhook, API-сервер и веб-панель).

Контракты выполнения (Completion contracts)

Обычный /goal <текст> работает, но размытая цель ведёт к размытой оценке — судья может проверить только то, что вы указали. Контракт добавляет структурированные критерии.

Поле Значение
outcome Конечное состояние, которое должно быть истинным.
verification Конкретный тест / команда / артефакт, доказывающий результат.
constraints Что нельзя менять или ломать.
boundaries Какие файлы, директории, инструменты входят в область.
stop_when Условие, при котором Hermes должен остановиться и спросить пользователя.

Два способа создать контракт

1. Автоматически через /goal draft (рекомендуется):

/goal draft Миграция auth-сервиса с session cookies на JWT

Hermes расширяет однострочную цель в полноценный контракт через вспомогательную модель goal_judge, устанавливает его и показывает результат. Если aux-модель недоступна, используется обычный формат — создание цели никогда не блокируется.

2. Inline-синтаксис с полями:

/goal Миграция auth на JWT
verify: pytest tests/auth проходит
constraints: сохранить форму ответа /login
boundaries: трогать только services/auth и тесты
stop when: потребовалась миграция схемы БД

Первые строки без двоеточий — заголовок цели; распознанные префиксы полей (verify:, constraints:, preserve:, boundaries:, scope:, stop when:, blocked: и т.д.) заполняют контракт. Обычная цель с двоеточием в тексте (Fix bug: the parser drops commas) не искажается.

Просмотреть контракт: /goal show. Контракты сохраняются в SessionDB.state_meta и переживают /resume.

Дополнительные критерии: /subgoal

Во время активной цели можно добавить дополнительные критерии без сброса цикла:

Команда Описание
/subgoal <текст> Добавить критерий к активной цели.
/subgoal Показать пронумерованный список критериев.
/subgoal remove <N> Удалить N-й критерий (с 1).
/subgoal clear Удалить все критерии, сохранив основную цель.

Каждый вызов добавляет нумерованный пункт; промпт продолжения и промпт судьи перестраиваются с учётом всех subgoal — цель не будет отмечена как выполненная, пока не удовлетворены все критерии. Сохраняются в SessionDB.state_meta вместе с целью.

Парковка на фоновые процессы

Некоторые цели зависят от длительных фоновых задач (CI, сборка, тесты). Без автоматической парковки цикл будет каждый ход спрашивать «готово?» — напрасная трата бюджета.

Парковка автоматическая. Каждый ход судья видит фоновые процессы агента (реестр terminal(background=true) — pid, uptime, вывод, watch_patterns / notify_on_complete). Когда прогресс реально зависит от процесса, судья возвращает wait вместо continue — цикл паркуется до завершения ожидания. Судья может также парковаться на время (wait_for_seconds) для backoff.

  • wait_on_session <id> — освобождается при срабатывании триггера процесса (выход или watch_patterns).
  • wait_on_pid <pid> — освобождается при завершении процесса.
  • wait_for_seconds <n> — освобождается через N секунд.

/goal status показывает ⏳ Goal (parked …) во время парковки. Команды /goal wait и /goal unwait — ручная альтернатива. Парковка сохраняется в SessionDB.state_meta и переживает /resume. Если PID уже завершился или время истекло — барьер снимается автоматически.

Поведение

Судья

После каждого хода Hermes вызывает вспомогательную модель с:

  • Текстом стоячей цели
  • Последним ответом агента (~4 КБ текста)
  • Системным промптом с инструкцией ответить строгим JSON: {"done": bool, "reason": "..."}

Судья намеренно консервативен: цель считается выполненной только при явном подтверждении, когда конечный результат чётко произведён, или когда цель недостижима / заблокирована (обрабатывается как DONE с указанием причины, чтобы не тратить бюджет).

Отказоустойчивость (fail-open)

Если судья ошибается (сетевой сбой, некорректный ответ, недоступность aux-клиента), Hermes считает вердикт continue — сломанный судья никогда не блокирует прогресс. Бюджет ходов — основной ограничитель.

Бюджет ходов

По умолчанию — 20 ходов продолжения (goals.max_turns в config.yaml). При исчерпании:

⏸ Goal paused — 20/20 turns used. Use /goal resume to keep going, or /goal clear to stop.

/goal resume сбрасывает счётчик на ноль — можно работать управляемыми порциями.

Приоритет пользовательских сообщений

Любое реальное сообщение, отправленное во время активной цели, обрабатывается раньше автоматического продолжения. В CLI сообщение попадает в _pending_input перед очередью; в шлюзе — через FIFO адаптера. Судья проверяет снова после вашего хода — если он завершил цель, цикл остановится.

Безопасность в шлюзе (mid-run)

Пока агент работает, команды /goal status, /goal pause, /goal clear, /goal wait, /goal unwait безопасны — они затрагивают только контрольную плоскость. Установка новой цели (/goal <новый текст>) отклоняется с просьбой сначала выполнить /stop.

Кэш промптов

Промпт продолжения — обычное user-role сообщение, добавленное в историю. Он не меняет системный промпт, не переключает инструменты и не инвалидирует кэш промптов. 20-ходовая цель стоит столько же по кэшу, сколько 20 обычных ходов.

Конфигурация

В ~/.hermes/config.yaml:

goals:
  # Максимальное количество ходов до автопаузы. По умолчанию 20.
  max_turns: 20

Для переадресации судьи на быструю дешёвую модель:

auxiliary:
  goal_judge:
    provider: openrouter
    model: google/gemini-3-flash-preview

По умолчанию судья использует основную модель (см. Auxiliary Models). Вызов судьи мал (~200 токенов за ход), поэтому дешёвая модель — оптимальный выбор.

Состояние цели хранится в SessionDB.state_meta по ключу goal:<session_id>. После перезапуска можно возобновить /resume — цель сохраняется в точности (активная, приостановленная или завершённая).