sidebar_position: 11 title: "Cron Internals" description: "How Hermes stores, schedules, edits, pauses, skill-loads, and delivers cron jobs" lang: ru
Внутреннее устройство Cron
Подсистема cron обеспечивает выполнение задач по расписанию — от простых одноразовых задержек до повторяющихся заданий cron-выражения с внедрением навыков и кросс-платформенной доставкой.
Ключевые файлы
| Файл | Цель |
|---|---|
cron/jobs.py |
Модель задания, хранилище, атомарное чтение/запись на jobs.json |
cron/scheduler.py |
Цикл планировщика — обнаружение выполнения заданий, отслеживание повторений |
tools/cronjob_tools.py |
Регистрация и обработчик инструмента cronjob, ориентированного на модель |
gateway/run.py |
Интеграция шлюза — тиканье cron в длительном цикле |
hermes_cli/cron.py |
CLI hermes cron подкоманды |
Модель планирования
Поддерживаются четыре формата расписания:
| Формат | Пример | Поведение |
|---|---|---|
| Относительная задержка | 30m, 2h, 1d |
Однократный, срабатывает по истечении указанного времени |
| Интервал | every 2h, every 30m |
Повторяющиеся пожары через определенные промежутки времени |
| Выражение Cron | 0 9 * * * |
Стандартный синтаксис cron из 5 полей (минута, час, день, месяц, день недели) |
| Временная метка ISO | 2025-01-15T09:00:00 |
Одиночный выстрел, выстрел в точное время |
Поверхность, обращенная к модели, представляет собой единый инструмент cronjob с операциями в стиле действий: create, list, update, pause, resume, run, remove.
Хранилище заданий
Задания хранятся в ~/.hermes/cron/jobs.json с семантикой атомарной записи (запись во временный файл, затем переименование). Каждая запись о работе содержит:
{
"id": "a1b2c3d4e5f6",
"name": "Daily briefing",
"prompt": "Summarize today's AI news and funding rounds",
"schedule": {
"kind": "cron",
"expr": "0 9 * * *",
"display": "0 9 * * *"
},
"skills": ["ai-funding-daily-report"],
"deliver": "telegram:-1001234567890",
"repeat": {
"times": null,
"completed": 42
},
"state": "scheduled",
"enabled": true,
"next_run_at": "2025-01-16T09:00:00Z",
"last_run_at": "2025-01-15T09:00:00Z",
"last_status": "ok",
"created_at": "2025-01-01T00:00:00Z",
"model": null,
"provider": null,
"script": null
}
Состояния жизненного цикла задания
| Государство | Значение |
|---|---|
scheduled |
Активен, выстрелит в следующее запланированное время |
paused |
Приостановлено — не будет срабатывать, пока не возобновится |
completed |
Повторный отсчет исчерпан или произведен одиночный выстрел |
running |
Выполняется в данный момент (переходное состояние) |
Обратная совместимость
Более старые задания могут иметь одно поле skill вместо массива skills. Планировщик нормализует это во время загрузки — один skill повышается до skills: [skill].
Время выполнения планировщика
Тиковый цикл
Планировщик запускается периодически (по умолчанию: каждые 60 секунд):
tick()
1. Acquire scheduler lock (prevents overlapping ticks)
2. Load all jobs from jobs.json
3. Filter to due jobs (next_run <= now AND state == "scheduled")
4. For each due job:
a. Set state to "running"
b. Create fresh AIAgent session (no conversation history)
c. Load attached skills in order (injected as user messages)
d. Run the job prompt through the agent
e. Deliver the response to the configured target
f. Update run_count, compute next_run
g. If repeat count exhausted → state = "completed"
h. Otherwise → state = "scheduled"
5. Write updated jobs back to jobs.json
6. Release scheduler lock
Интеграция шлюза
В режиме шлюза планировщик работает в выделенном фоновом потоке (_start_cron_ticker в gateway/run.py), который вызывает scheduler.tick() каждые 60 секунд одновременно с обработкой сообщений.
В режиме CLI задания cron запускаются только при запуске команд hermes cron или во время активных сеансов CLI.
Свежая изоляция сеанса
Каждое задание cron выполняется в совершенно новом сеансе агента:
- Нет истории разговоров из предыдущих запусков
- Нет памяти о предыдущих выполнениях cron (если они не сохранены в памяти/файлах)
- Подсказка должна быть автономной — задания cron не могут задавать уточняющие вопросы.
- Набор инструментов
cronjobотключен (защита рекурсии)
Вакансии, требующие навыков
Задание cron может прикрепить один или несколько навыков через поле skills. Во время выполнения:
- Навыки загружаются в указанном порядке
- Содержимое SKILL.md каждого навыка вводится как контекст.
- Приглашение к заданию добавляется как инструкция к задаче.
- Агент обрабатывает объединенный контекст навыка + подсказку.
Это позволяет многократно использовать проверенные рабочие процессы без вставки полных инструкций в подсказки cron. Например:
Create a daily funding report → attach "ai-funding-daily-report" skill
Задания, поддерживаемые скриптами
Джобс также может прикрепить скрипт Python через поле script. Сценарий запускается перед каждым поворотом агента, и его стандартный вывод вводится в приглашение в качестве контекста. Это обеспечивает сбор данных и шаблоны обнаружения изменений:
# ~/.hermes/scripts/check_competitors.py
import requests, json
# Fetch competitor release notes, diff against last run
# Print summary to stdout — agent analyzes and reports
Тайм-аут сценария по умолчанию составляет 120 секунд. _get_script_timeout() разрешает ограничение посредством трехуровневой цепочки:
- Переопределение на уровне модуля —
_SCRIPT_TIMEOUT(для тестов/монкейпатчей). Используется только в том случае, если оно отличается от значения по умолчанию. - Переменная среды —
HERMES_CRON_SCRIPT_TIMEOUT - Конфигурация —
cron.script_timeout_secondsвconfig.yaml(читается черезload_config()) - По умолчанию — 120 секунд.
Восстановление провайдера
run_job() передает настроенных пользователем резервных поставщиков и пул учетных данных в экземпляр AIAgent:
- Резервные поставщики — читается
fallback_providers(список) илиfallback_model(устаревший dict) изconfig.yaml, что соответствует шаблону_load_fallback_model()шлюза. Передается отfallback_model=доAIAgent.__init__, что нормализует оба формата в резервную цепочку. - Пул учетных данных — загружается через
load_pool(provider)изagent.credential_poolс использованием разрешенного имени поставщика среды выполнения. Проходит только тогда, когда у пула есть учетные данные (pool.has_credentials()). Включает ротацию ключей одного и того же поставщика при ошибках 429/ограничения скорости.
Это отражает поведение шлюза — без него агенты cron не смогут выполнить ограничения скорости, не пытаясь восстановиться.
Модель доставки
Результаты задания Cron могут быть доставлены на любую поддерживаемую платформу:
| Цель | Синтаксис | Пример |
|---|---|---|
| Происхождение чата | origin |
Доставить в чат, где была создана вакансия |
| Локальный файл | local |
Сохранить в ~/.hermes/cron/output/ |
| Телеграмма | telegram или telegram:<chat_id> |
telegram:-1001234567890 |
| Раздор | discord или discord:#channel |
discord:#engineering |
| слабый | slack |
Доставить на домашний канал Slack |
whatsapp |
Доставить на дом в WhatsApp | |
| Сигнал | signal |
Доставить в Signal |
| Матрица | matrix |
Доставить в домашнюю комнату Матрицы |
| Самое важное | mattermost |
Доставить в Mattermost домой |
| Электронная почта | email |
Доставка по электронной почте |
| СМС | sms |
Доставка по SMS |
| Домашний помощник | homeassistant |
Доставка в диалог высокой доступности |
| ДинТок | dingtalk |
Доставить в DingTalk |
| Фейшу | feishu |
Доставить в Фейшу |
| ВеКом | wecom |
Доставка в WeCom |
| Вэйсинь | weixin |
Доставка в Weixin (WeChat) |
| Синие пузыри | bluebubbles |
Доставка в iMessage через BlueBubbles |
| QQ-бот | qqbot |
Доставка в QQ (Tencent) через официальный API v2 |
Для тем Telegram используйте формат telegram:<chat_id>:<thread_id> (например, telegram:-1001234567890:17585).
перенос ответа
По умолчанию (cron.wrap_response: true) поставки cron обертываются:
- Заголовок, идентифицирующий имя и задачу cron.
- Нижний колонтитул, указывающий, что агент не может видеть доставленное сообщение в разговоре.
Префикс [SILENT] в ответе cron полностью подавляет доставку — это полезно для заданий, которым требуется только запись в файлы или выполнение побочных эффектов.
Изоляция сеанса
Доставки Cron НЕ отражаются в истории сеансов шлюза. Они существуют только в собственном сеансе задания cron. Это предотвращает нарушения чередования сообщений в беседе целевого чата.
Защита рекурсии
В сеансах Cron отключен набор инструментов cronjob. Это предотвращает:
- Запланированное задание по созданию новых заданий cron.
- Рекурсивное планирование, которое может привести к резкому увеличению использования токенов.
- Случайное изменение графика работы внутри задания.
Блокировка
Планировщик использует межпроцессную файловую блокировку (fcntl.flock в Unix, msvcrt.locking в Windows), чтобы предотвратить двукратное выполнение одного и того же пакета выполняемых заданий с помощью перекрывающихся тиков — даже между внутрипроцессным тикером шлюза и автономным hermes cron / ручным вызовом tick(). Если блокировку невозможно получить, tick() немедленно возвращает 0.
Интерфейс командной строки
hermes cron CLI обеспечивает прямое управление заданиями:
hermes cron list # Show all jobs
hermes cron create # Interactive job creation (alias: add)
hermes cron edit <job_id> # Edit job configuration
hermes cron pause <job_id> # Pause a running job
hermes cron resume <job_id> # Resume a paused job
hermes cron run <job_id> # Trigger immediate execution
hermes cron remove <job_id> # Delete a job