# 心跳

「心跳」在 QwenPaw 里指的是：**按固定间隔，用你写好的一段「问题」去问 QwenPaw，并可选择把 QwenPaw 的回复发到你上次对话的频道**。适合做「定期自检、每日摘要、定时提醒」——不用你主动发消息，QwenPaw 到点就干活。

多智能体模式下，**每个智能体**各自有一份 **HEARTBEAT.md** 和 **heartbeat** 配置（在该智能体的 workspace 目录里）。在 [控制台](./console) 里也可以打开或关闭心跳、改间隔等（**控制 → 心跳**）。

如果你还没看过 [项目介绍](./intro)，建议先看一眼那里对「心跳」和「频道」的说明。

---

## 心跳是怎么工作的？

1. 在当前智能体的 workspace 里有一个**心跳查询文件**（默认文件名为 **HEARTBEAT.md**，可用环境变量 `QWENPAW_HEARTBEAT_FILE` 改名）。里面写的是**每次心跳要问 QwenPaw 的内容**（一段或几段话都行，QwenPaw 会当成一条用户消息）。
2. 当配置里 **`enabled` 为 true** 时，系统按你配置的 **every**（间隔字符串或五段 Cron）执行一次：读取该文件 → 用这段内容去问 QwenPaw → QwenPaw 回复。
3. **发不发到频道** 由配置里的 **target** 决定：
   - **main**：只跑 QwenPaw，不把回复发到任何频道（适合只做「自检」、结果自己看日志或别处）。
   - **last**：把 QwenPaw 的回复发到你**上次和 QwenPaw 对话的那个频道/会话**（例如上次你在钉钉和它聊，这次心跳的回复就发到钉钉）。

还可以设置 **active hours**（活跃时段）：只在每天的某段时间内跑心跳（例如 08:00–22:00），其余时间不跑。

---

## 第一步：写 HEARTBEAT.md

**路径（多智能体，常见情况）**：`<QWENPAW_WORKING_DIR>/workspaces/<agent_id>/HEARTBEAT.md`。
`<QWENPAW_WORKING_DIR>` 默认是 `~/.qwenpaw`，也可用环境变量 `QWENPAW_WORKING_DIR` 覆盖；`<agent_id>` 与当前智能体一致（例如 `default`）。

文件名默认 `HEARTBEAT.md`，可通过 **`QWENPAW_HEARTBEAT_FILE`** 改成别的名字；路径始终是「该智能体 workspace 根目录 + 该文件名」。

内容就是「每次要问 QwenPaw 什么」，纯文本或 Markdown 都行，QwenPaw 会整体当作一条用户消息。

示例（你可以按自己需求改）：

```markdown
# Heartbeat checklist

- 扫描收件箱紧急邮件
- 查看未来 2h 的日历
- 检查待办是否卡住
- 若安静超过 8h，轻量 check-in
```

初始化时如果执行过 `qwenpaw init`（没加 `--defaults`），会提示你是否编辑 HEARTBEAT.md；选是会用系统默认编辑器打开。你也可以之后随时用任何编辑器改这个文件，保存即可，下次心跳会用到新内容。

---

## 第二步：配置心跳

![heartbeat](https://img.alicdn.com/imgextra/i2/O1CN0197MAPx2002prwqU5N_!!6000000006786-2-tps-3822-2070.png)

推荐在 console 的 **心跳**页面进行配置。如果想通过修改agent.json实现，参考以下内容。

**间隔、开关、发到哪、执行超时、活跃时段** 读自当前智能体的 **`workspaces/<agent_id>/agent.json`** 里的 **`heartbeat`** 字段（与控制台保存的配置一致）。
从旧版迁移时，历史上写在根目录 **`config.json`** 的 `agents.defaults.heartbeat` 会合并进默认智能体的 `agent.json`；新配置请以 **`agent.json` 为准**。

| 字段               | 含义                                                                                                                                                                                                                  |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **enabled**        | 是否开启心跳。**默认 false**；只有为 **true** 时才会按计划执行。                                                                                                                                                      |
| **every**          | 多久跑一次：间隔字符串（如 `"30m"`、`"1h"`、`"2h30m"`、`"90s"`），**或** 空格分隔的 **五段 Cron**（分 时 日 月 周几，与定时任务相同的五段写法，例如每天 9:00：`"0 9 * * *"`）。使用 Cron 时由进程内调度器的时区解析。 |
| **target**         | **main** 不发送到频道；**last** 发到该智能体 `last_dispatch` 记录的频道；**inbox** 发送到收件箱中。                                                                                                                   |
| **timeoutSeconds** | 单次心跳执行的最长时间，单位秒。**默认 300**，有效范围 **1–3600**。                                                                                                                                                   |
| **activeHours**    | 可选，只在每天这段时间内跑：`{ "start": "08:00", "end": "22:00" }`。                                                                                                                                                  |

`every` 未写时的默认间隔以程序内置为准（当前默认约为 **6 小时**，仍以你环境里的版本为准）。

示例（开启心跳，只跑 QwenPaw、不发到频道，每 30 分钟）——写在对应智能体的 **`agent.json`** 中：

```json
{
  "heartbeat": {
    "enabled": true,
    "every": "30m",
    "target": "main"
  }
}
```

示例（发到上次对话的频道，每 1 小时，且只在 08:00–22:00 跑）：

```json
{
  "heartbeat": {
    "enabled": true,
    "every": "1h",
    "target": "last",
    "timeoutSeconds": 300,
    "activeHours": { "start": "08:00", "end": "22:00" }
  }
}
```

改完保存 config.json；若服务在跑，会按新配置生效（部分实现可能需重启，以实际为准）。

---

## 和「定时任务」的区别

|          | 心跳                       | 定时任务 (cron)              |
| -------- | -------------------------- | ---------------------------- |
| **数量** | 只有一份（HEARTBEAT.md）   | 可以建很多个                 |
| **间隔** | 一个全局间隔               | 每个独立设定时间             |
| **投递** | 可选发到「上次频道」或不发 | 每个独立指定频道和用户       |
| **适用** | 固定的一套自检/摘要        | 多条不同时间、不同内容的任务 |

> 需要「每天 9 点发早安」「每 2 小时问待办并发到钉钉」这类多条任务？请使用 [定时任务](./cron)（或 [CLI](./cli) 的 `qwenpaw cron create`），而不是心跳。

---

## 相关页面

- [项目介绍](./intro) — 这个项目可以做什么
- [控制台](./console) — Web 里开关心跳、改间隔
- [频道配置](./channels) — 先接好频道，target=last 才有「上次频道」可发
- [定时任务](./cron) — 管理多条独立计划任务
- [CLI](./cli) — init 时配置心跳、cron 定时任务
- [配置与工作目录](./config) — config.json、agent.json 与工作目录
