跳到主要内容

Cron 内部机制

cron 子系统提供计划任务执行——从简单的一次性延迟到具有技能注入和跨平台交付的重复 cron 表达式作业。

关键文件

文件目的
cron/jobs.py作业模型、存储、对 jobs.json 的原子读/写
cron/scheduler.py调度器循环 — 到期作业检测、执行、重复跟踪
tools/cronjob_tools.py面向模型的 cronjob 工具注册与处理器
gateway/run.py网关集成——长时间运行循环中的 cron 滴答作响
hermes_cli/cron.pyhermes cron CLI 子命令

调度模型

支持四种计划格式:

格式示例行为
相对延迟30m2h1d一发,指定持续时间后开火
间隔every 2hevery 30m定期发生、定期发生火灾
Cron 表达式0 9 * * *0 9 * * *标准 5 字段 cron 语法(分钟、小时、日、月、工作日)
ISO 时间戳2025-01-15T09:00:002025-01-15T09:00:00一发,准时开火

面向模型的表面是一个 cronjob 工具,具有动作式操作:createlistupdatepauseresumerunremove

作业存储

作业以原子写入语义存储在 ~/.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
}

作业生命周期状态

状态意义
scheduledscheduled活动,将在下一个预定时间触发
pausedpaused已暂停 — 在恢复之前不会触发
completedcompleted重复计数已用尽或已发射一发
runningrunning当前正在执行(瞬态)

向后兼容性

较旧的作业可能有一个 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

网关集成

在网关模式下,调度程序滴答被集成到网关的主事件循环中。网关在其定期维护周期中调用 scheduler.tick() ,该周期与消息处理一起运行。

在 CLI 模式下,cron 作业仅在运行 hermes cron 命令时或在活动 CLI 会话期间触发。

新会话隔离

每个 cron 作业都在全新的代理会话中运行:

  • 没有之前运行的对话历史记录
  • 没有先前 cron 执行的记忆(除非持久化到内存/文件)
  • 提示必须是独立的 - cron 作业不能提出澄清问题
  • cronjob 工具集已禁用(递归防护)

技能支持的工作

cron 作业可以通过 skills 字段附加一项或多项技能。执行时:

1.技能按照指定顺序加载 2.每个技能的SKILL.md内容作为上下文注入 3. 作业提示作为任务指令附加 4. 代理处理组合的技能上下文+提示

这可以实现可重用、经过测试的工作流程,而无需将完整的指令粘贴到 cron 提示中。例如:

Create a daily funding report → attach "ai-funding-daily-report" skill

脚本支持的作业

作业还可以通过 script 字段附加 Python 脚本。该脚本在每个代理轮流之前运行,并且其标准输出作为上下文注入到提示中。这使得数据收集和变化检测模式成为可能:

# ~/.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() 通过三层链解决限制:

  1. 模块级覆盖_SCRIPT_TIMEOUT (用于测试/monkeypatching)。仅当与默认值不同时才使用。
  2. 环境变量HERMES_CRON_SCRIPT_TIMEOUT
  3. 配置config.yaml 中的 cron.script_timeout_seconds (通过 load_config() 读取)
  4. 默认 — 120 秒

提供商恢复

run_job() 将用户配置的后备大模型提供商(provider)和凭证池传递到 AIAgent 实例中:

  • 后备大模型提供商(provider) — 从 config.yaml 读取 fallback_providers (列表)或 fallback_model (旧版字典),匹配网关的 _load_fallback_model() 模式。作为 fallback_model= 传递到 AIAgent.__init__,这将两种格式标准化为后备链。
  • 凭证池 — 使用解析的运行时大模型提供商(provider)名称通过 load_pool(provider)agent.credential_pool 加载。仅当池具有凭据 (pool.has_credentials()) 时才通过。针对 429/速率限制错误启用同一提供商密钥轮换。

这反映了网关的行为——没有它,cron 代理将在速率限制上失败,而不尝试恢复。

交付模式

Cron 作业结果可以传送到任何支持的平台:

目标语法示例
起源聊天originorigin交付到创建职位的聊天室
本地文件locallocal保存到 ~/.hermes/cron/output/
电报telegramtelegram:<chat_id>telegram:-1001234567890
不和谐discorddiscord:#channeldiscord:#engineering
松弛slackslack交付到 Slack 主频道
WhatsAppwhatsappwhatsapp送货到 WhatsApp 首页
信号signalsignal交付给信号
矩阵matrixmatrix送到 Matrix 家庭房间
最重要mattermostmattermost送货到 Mattermost 家
电子邮件emailemail通过电子邮件发送
短信smssms通过短信发送
家庭助理homeassistanthomeassistant交付给 HA 对话
钉钉dingtalkdingtalk发送至钉钉
飞书feishufeishu发送至飞书
微康wecomwecom交付至WeCom
微信weixinweixin发送至微信
蓝色泡泡bluebubblesbluebubbles通过 BlueBubbles 发送至 iMessage
QQ机器人qqbotqqbot通过官方API v2 投递至QQ(腾讯)

对于 Telegram 主题,请使用格式 telegram:<chat_id>:<thread_id>(例如 telegram:-1001234567890:17585)。

响应包装

默认情况下(cron.wrap_response: true),cron 交付包含以下内容:

  • 标识 cron 作业名称和任务的标头
  • 页脚指出客服人员无法在对话中看到已传递的消息

cron 响应中的 [SILENT] 前缀完全抑制传递——对于只需要写入文件或执行副作用的作业很有用。

会话隔离

Cron 交付不会镜像到网关会话对话历史记录中。它们仅存在于 cron 作业自己的会话中。这可以防止目标聊天对话中出现消息交替违规。

递归守卫

Cron 运行会话已禁用 cronjob 工具集。这可以防止:

  • 创建新的 cron 作业的预定作业
  • 递归调度可能会导致令牌使用量激增
  • 工作内部的工作安排意外改变

锁定

调度程序使用基于文件的锁定来防止重叠的滴答执行相同的到期作业批次两次。这在网关模式中很重要,如果前一个刻度花费的时间比刻度间隔长,则多个维护周期可能会重叠。

CLI 界面

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

相关文档