心跳(网关)

心跳(网关)

适用范围

在以下情况使用此页面:

  • 调整心跳节奏或消息传递
  • 决定是使用心跳还是 cron 来执行计划任务

心跳 vs Cron? 有关何时使用每个的指导,请参阅 Cron vs 心跳

心跳在主会话中运行 定期代理轮次,以便模型可以显示需要注意的任何内容,而不会向您发送垃圾邮件。

快速入门(初学者)

  1. 保持心跳启用(默认为 30m,或 Anthropic OAuth/setup-token 为 1h)或设置您自己的节奏。
  2. 在代理工作空间中创建一个小的 HEARTBEAT.md 检查清单(可选但推荐)。
  3. 决定心跳消息应该去哪里(target: "last" 是默认值)。
  4. 可选:启用心跳推理传递以提高透明度。
  5. 可选:将心跳限制在活动时间内(本地时间)。

配置示例:

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m",
        target: "last",
        // activeHours: { start: "08:00", end: "24:00" },
        // includeReasoning: true, // 可选:还发送单独的 `Reasoning:` 消息
      }
    }
  }
}

默认值

  • 间隔:30m(或当 Anthropic OAuth/setup-token 是检测到的身份验证模式时为 1h)。设置 agents.defaults.heartbeat.every 或每代理 agents.list[].heartbeat.every;使用 0m 禁用。
  • 提示正文(可通过 agents.defaults.heartbeat.prompt 配置): 如果存在 HEARTBEAT.md,请阅读它(工作空间上下文)。严格遵循它。不要从以前的聊天中推断或重复旧任务。如果不需要注意,请回复 HEARTBEAT_OK。
  • 心跳提示作为用户消息 逐字发送。系统提示包括"Heartbeat"部分,并且运行在内部被标记。
  • 活动时间(heartbeat.activeHours)在配置的时区中检查。在窗口之外,心跳被跳过,直到窗口内的下一个刻度。

心跳提示的用途

默认提示是有意宽泛的:

  • 后台任务:“考虑未完成的任务"促使代理审查后续操作(收件箱、日历、提醒、排队的工作)并显示任何紧急内容。
  • 人工签到:“白天有时检查您的人类"促使偶尔的轻量级"您需要什么?“消息,但通过使用您配置的本地时区避免夜间垃圾邮件(参见 /concepts/timezone)。

如果您希望心跳执行非常特定的操作(例如"检查 Gmail PubSub 统计信息"或"验证网关健康状况”),请将 agents.defaults.heartbeat.prompt(或 agents.list[].heartbeat.prompt)设置为自定义正文(逐字发送)。

响应契约

  • 如果不需要注意,请回复 HEARTBEAT_OK
  • 在心跳运行期间,当 HEARTBEAT_OK 出现在回复的 开始或结束 时,Moltbot 将其视为确认。令牌被剥离,如果剩余内容 ackMaxChars(默认:300),则回复被丢弃。
  • 如果 HEARTBEAT_OK 出现在回复的 中间,则不会特殊处理。
  • 对于警报,不要包括 HEARTBEAT_OK;仅返回警报文本。

在心跳之外,消息开始/结束处的杂散 HEARTBEAT_OK 被剥离并记录;仅 HEARTBEAT_OK 的消息被丢弃。

配置

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m",           // 默认:30m(0m 禁用)
        model: "anthropic/claude-opus-4-5",
        includeReasoning: false, // 默认:false(在可用时传递单独的 Reasoning: 消息)
        target: "last",         // last | none | <channel id>(核心或插件,例如 "bluebubbles")
        to: "+15551234567",     // 可选通道特定覆盖
        prompt: "如果存在 HEARTBEAT.md,请阅读它(工作空间上下文)。严格遵循它。不要从以前的聊天中推断或重复旧任务。如果不需要注意,请回复 HEARTBEAT_OK。",
        ackMaxChars: 300         // HEARTBEAT_OK 之后允许的最大字符数
      }
    }
  }
}

作用域和优先级

  • agents.defaults.heartbeat 设置全局心跳行为。
  • agents.list[].heartbeat 在顶部合并;如果任何代理有 heartbeat 块,仅这些代理运行心跳。
  • channels.defaults.heartbeat 为所有通道设置可见性默认值。
  • channels.<channel>.heartbeat 覆盖通道默认值。
  • channels.<channel>.accounts.<id>.heartbeat(多账户通道)覆盖每通道设置。

每代理心跳

如果任何 agents.list[] 条目包括 heartbeat 块,仅这些代理运行心跳。每代理块在 agents.defaults.heartbeat 之上合并(因此您可以设置一次共享默认值并每代理覆盖)。

示例:两个代理,仅第二个代理运行心跳。

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m",
        target: "last"
      }
    },
    list: [
      { id: "main", default: true },
      {
        id: "ops",
        heartbeat: {
          every: "1h",
          target: "whatsapp",
          to: "+15551234567",
          prompt: "如果存在 HEARTBEAT.md,请阅读它(工作空间上下文)。严格遵循它。不要从以前的聊天中推断或重复旧任务。如果不需要注意,请回复 HEARTBEAT_OK。"
        }
      }
    ]
  }
}

字段说明

  • every:心跳间隔(持续时间字符串;默认单位 = 分钟)。
  • model:心跳运行的可选模型覆盖(provider/model)。
  • includeReasoning:启用时,还在可用时传递单独的 Reasoning: 消息(与 /reasoning on 形状相同)。
  • session:心跳运行的可选会话键。
    • main(默认):代理主会话。
    • 显式会话键(从 moltbot sessions --json会话 CLI 复制)。
    • 会话键格式:参见 会话群组
  • target
    • last(默认):传递到上次使用的外部通道。
    • 显式通道:whatsapp / telegram / discord / googlechat / slack / msteams / signal / imessage
    • none:运行心跳但 不传递外部。
  • to:可选收件人覆盖(通道特定 id,例如 WhatsApp 的 E.164 或 Telegram 聊天 id)。
  • prompt:覆盖默认提示正文(不合并)。
  • ackMaxChars:在 HEARTBEAT_OK 之后传递之前允许的最大字符数。

传递行为

  • 心跳默认在代理的主会话(agent:<id>:<mainKey>)中运行,或在 session.scope = "global" 时在 global 中运行。设置 session 覆盖到特定通道会话(Discord/WhatsApp/等)。
  • session 仅影响运行上下文;传递由 targetto 控制。
  • 要传递到特定通道/收件人,请设置 target + to。使用 target: "last",传递使用该会话的上一个外部通道。
  • 如果主队列忙碌,心跳被跳过并在稍后重试。
  • 如果 target 解析为无外部目的地,运行仍然发生但不发送出站消息。
  • 仅心跳回复 保持会话活动;恢复上一个 updatedAt,因此空闲过期正常工作。

可见性控制

默认情况下,HEARTBEAT_OK 确认被抑制,而警报内容被传递。您可以按通道或按账户调整此设置:

channels:
  defaults:
    heartbeat:
      showOk: false      # 隐藏 HEARTBEAT_OK(默认)
      showAlerts: true   # 显示警报消息(默认)
      useIndicator: true # 发出指示器事件(默认)
  telegram:
    heartbeat:
      showOk: true       # 在 Telegram 上显示 OK 确认
  whatsapp:
    accounts:
      work:
        heartbeat:
          showAlerts: false # 为此帐户抑制警报传递

优先级:每账户 → 每通道 → 通道默认值 → 内置默认值。

每个标志的作用

  • showOk:当模型返回仅 OK 的回复时发送 HEARTBEAT_OK 确认。
  • showAlerts:当模型返回非 OK 回复时发送警报内容。
  • useIndicator:为 UI 状态表面发出指示器事件。

如果 所有三个 都为 false,Moltbot 将完全跳过心跳运行(无模型调用)。

每通道 vs 每账户示例

channels:
  defaults:
    heartbeat:
      showOk: false
      showAlerts: true
      useIndicator: true
  slack:
    heartbeat:
      showOk: true # 所有 Slack 帐户
    accounts:
      ops:
        heartbeat:
          showAlerts: false # 仅为 ops 帐户抑制警报
  telegram:
    heartbeat:
      showOk: true

常见模式

目标配置
默认行为(静默 OK,启用警报)(无需配置)
完全静默(无消息,无指示器)channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: false }
仅指示器(无消息)channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: true }
仅在一个通道中显示 OKchannels.telegram.heartbeat: { showOk: true }

HEARTBEAT.md(可选)

如果工作空间中存在 HEARTBEAT.md 文件,默认提示会告诉代理读取它。将其视为您的"心跳检查清单”:小、稳定,并且可以每 30 分钟安全地包含一次。

如果 HEARTBEAT.md 存在但实际上为空(只有空行和 markdown 标题,如 # Heading),Moltbot 会跳过心跳运行以节省 API 调用。 如果文件丢失,心跳仍然运行,模型决定做什么。

保持它很小(简短检查清单或提醒),以避免提示膨胀。

示例 HEARTBEAT.md

# 心跳检查清单

- 快速扫描:收件箱中有什么紧急情况吗?
- 如果是白天,如果没有其他待处理,请进行轻量级签到。
- 如果任务被阻止,写下 *缺少什么* 并在下次询问 Peter。

代理可以更新 HEARTBEAT.md 吗?

可以 — 如果您要求它。

HEARTBEAT.md 只是代理工作空间中的普通文件,因此您可以告诉代理(在正常聊天中)类似:

  • “更新 HEARTBEAT.md 以添加每日日历检查。”
  • “重写 HEARTBEAT.md,使其更短并专注于收件箱后续操作。”

如果您希望这主动发生,您还可以在心跳提示中包括显式行,例如:“如果检查清单变得陈旧,请用更好的检查清单更新 HEARTBEAT.md。”

安全说明:不要将机密(API 密钥、电话号码、私有令牌)放入 HEARTBEAT.md — 它成为提示上下文的一部分。

手动唤醒(按需)

您可以将系统事件排队并使用以下命令触发即时心跳:

moltbot system event --text "检查紧急后续操作" --mode now

如果多个代理配置了 heartbeat,手动唤醒将立即运行每个代理心跳。

使用 --mode next-heartbeat 等待下一个计划的刻度。

推理传递(可选)

默认情况下,心跳仅传递最终的"答案"负载。

如果您想要透明度,请启用:

  • agents.defaults.heartbeat.includeReasoning: true

启用后,心跳还将传递带有前缀 Reasoning: 的单独消息(与 /reasoning on 形状相同)。当代理管理多个会话/编码,并且您想看到它决定 ping 您的原因时,这可能很有用 — 但它也可能泄露比您想要的更多内部细节。最好在群组聊天中保持关闭。

成本意识

心跳运行完整的代理轮次。较短的间隔会消耗更多令牌。保持 HEARTBEAT.md 很小,并考虑更便宜的 modeltarget: "none"(如果您只想要内部状态更新)。