first commit
This commit is contained in:
47
content/automation/auth-monitoring.md
Normal file
47
content/automation/auth-monitoring.md
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
read_when:
|
||||
- 设置认证过期监控或告警
|
||||
- 自动化 Claude Code / Codex OAuth 刷新检查
|
||||
summary: 监控模型提供商的 OAuth 过期状态
|
||||
title: 认证监控
|
||||
x-i18n:
|
||||
generated_at: "2026-02-03T10:03:53Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: eef179af9545ed7ab881f3ccbef998869437fb50cdb4088de8da7223b614fa2b
|
||||
source_path: automation/auth-monitoring.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 认证监控
|
||||
|
||||
OpenClaw 通过 `openclaw models status` 提供 OAuth 过期健康状态。请使用该命令进行自动化和告警;脚本是为手机工作流程提供的可选附加功能。
|
||||
|
||||
## 推荐方式:CLI 检查(可移植)
|
||||
|
||||
```bash
|
||||
openclaw models status --check
|
||||
```
|
||||
|
||||
退出码:
|
||||
|
||||
- `0`:正常
|
||||
- `1`:凭证过期或缺失
|
||||
- `2`:即将过期(24 小时内)
|
||||
|
||||
此方式适用于 cron/systemd,无需额外脚本。
|
||||
|
||||
## 可选脚本(运维 / 手机工作流程)
|
||||
|
||||
这些脚本位于 `scripts/` 目录下,属于**可选**内容。它们假定你可以通过 SSH 访问 Gateway 网关主机,并针对 systemd + Termux 进行了调优。
|
||||
|
||||
- `scripts/claude-auth-status.sh` 现在使用 `openclaw models status --json` 作为数据来源(如果 CLI 不可用则回退到直接读取文件),因此请确保 `openclaw` 在定时器的 `PATH` 中。
|
||||
- `scripts/auth-monitor.sh`:cron/systemd 定时器目标;发送告警(ntfy 或手机)。
|
||||
- `scripts/systemd/openclaw-auth-monitor.{service,timer}`:systemd 用户定时器。
|
||||
- `scripts/claude-auth-status.sh`:Claude Code + OpenClaw 认证检查器(完整/json/简洁模式)。
|
||||
- `scripts/mobile-reauth.sh`:通过 SSH 引导的重新认证流程。
|
||||
- `scripts/termux-quick-auth.sh`:一键小部件状态查看 + 打开认证 URL。
|
||||
- `scripts/termux-auth-widget.sh`:完整的引导式小部件流程。
|
||||
- `scripts/termux-sync-widget.sh`:同步 Claude Code 凭证 → OpenClaw。
|
||||
|
||||
如果你不需要手机自动化或 systemd 定时器,可以跳过这些脚本。
|
||||
424
content/automation/cron-jobs.md
Normal file
424
content/automation/cron-jobs.md
Normal file
@@ -0,0 +1,424 @@
|
||||
---
|
||||
read_when:
|
||||
- 调度后台任务或唤醒
|
||||
- 配置需要与心跳一起或并行运行的自动化
|
||||
- 在心跳和定时任务之间做选择
|
||||
summary: Gateway网关调度器的定时任务与唤醒
|
||||
title: 定时任务
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T19:37:32Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: d43268b0029f1b13d0825ddcc9c06a354987ea17ce02f3b5428a9c68bf936676
|
||||
source_path: automation/cron-jobs.md
|
||||
workflow: 14
|
||||
---
|
||||
|
||||
# 定时任务(Gateway网关调度器)
|
||||
|
||||
> **定时任务还是心跳?** 请参阅[定时任务与心跳对比](/automation/cron-vs-heartbeat)了解何时使用哪种方式。
|
||||
|
||||
定时任务是 Gateway网关内置的调度器。它持久化任务、在合适的时间唤醒智能体,并可选择将输出发送回聊天。
|
||||
|
||||
如果你想要 _"每天早上运行"_ 或 _"20 分钟后提醒智能体"_,定时任务就是对应的机制。
|
||||
|
||||
## 简要概述
|
||||
|
||||
- 定时任务运行在 **Gateway网关内部**(而非模型内部)。
|
||||
- 任务持久化存储在 `~/.openclaw/cron/` 下,因此重启不会丢失计划。
|
||||
- 两种执行方式:
|
||||
- **主会话**:入队一个系统事件,然后在下一次心跳时运行。
|
||||
- **隔离式**:在 `cron:<jobId>` 中运行专用智能体轮次,可投递摘要(默认 announce)或不投递。
|
||||
- 唤醒是一等功能:任务可以请求"立即唤醒"或"下次心跳时"。
|
||||
|
||||
## 快速开始(可操作)
|
||||
|
||||
创建一个一次性提醒,验证其存在,然后立即运行:
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Reminder" \
|
||||
--at "2026-02-01T16:00:00Z" \
|
||||
--session main \
|
||||
--system-event "Reminder: check the cron docs draft" \
|
||||
--wake now \
|
||||
--delete-after-run
|
||||
|
||||
openclaw cron list
|
||||
openclaw cron run <job-id> --force
|
||||
openclaw cron runs --id <job-id>
|
||||
```
|
||||
|
||||
调度一个带投递功能的周期性隔离任务:
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Morning brief" \
|
||||
--cron "0 7 * * *" \
|
||||
--tz "America/Los_Angeles" \
|
||||
--session isolated \
|
||||
--message "Summarize overnight updates." \
|
||||
--announce \
|
||||
--channel slack \
|
||||
--to "channel:C1234567890"
|
||||
```
|
||||
|
||||
## 工具调用等价形式(Gateway网关定时任务工具)
|
||||
|
||||
有关规范的 JSON 结构和示例,请参阅[工具调用的 JSON 模式](/automation/cron-jobs#json-schema-for-tool-calls)。
|
||||
|
||||
## 定时任务的存储位置
|
||||
|
||||
定时任务默认持久化存储在 Gateway网关主机的 `~/.openclaw/cron/jobs.json` 中。Gateway网关将文件加载到内存中,并在更改时写回,因此仅在 Gateway网关停止时手动编辑才是安全的。请优先使用 `openclaw cron add/edit` 或定时任务工具调用 API 进行更改。
|
||||
|
||||
## 新手友好概述
|
||||
|
||||
将定时任务理解为:**何时**运行 + **做什么**。
|
||||
|
||||
1. **选择调度计划**
|
||||
- 一次性提醒 → `schedule.kind = "at"`(CLI:`--at`)
|
||||
- 重复任务 → `schedule.kind = "every"` 或 `schedule.kind = "cron"`
|
||||
- 如果你的 ISO 时间戳省略了时区,将被视为 **UTC**。
|
||||
|
||||
2. **选择运行位置**
|
||||
- `sessionTarget: "main"` → 在下一次心跳时使用主会话上下文运行。
|
||||
- `sessionTarget: "isolated"` → 在 `cron:<jobId>` 中运行专用智能体轮次。
|
||||
|
||||
3. **选择负载**
|
||||
- 主会话 → `payload.kind = "systemEvent"`
|
||||
- 隔离会话 → `payload.kind = "agentTurn"`
|
||||
|
||||
可选:一次性任务(`schedule.kind = "at"`)默认会在成功运行后删除。设置
|
||||
`deleteAfterRun: false` 可保留它(成功后会禁用)。
|
||||
|
||||
## 概念
|
||||
|
||||
### 任务
|
||||
|
||||
定时任务是一条存储记录,包含:
|
||||
|
||||
- 一个**调度计划**(何时运行),
|
||||
- 一个**负载**(做什么),
|
||||
- 可选的**投递**(输出发送到哪里)。
|
||||
- 可选的**智能体绑定**(`agentId`):在指定智能体下运行任务;如果缺失或未知,Gateway网关会回退到默认智能体。
|
||||
|
||||
任务通过稳定的 `jobId` 标识(用于 CLI/Gateway网关 API)。
|
||||
在智能体工具调用中,`jobId` 是规范字段;旧版 `id` 仍可兼容使用。
|
||||
一次性任务默认会在成功运行后自动删除;设置 `deleteAfterRun: false` 可保留它。
|
||||
|
||||
### 调度计划
|
||||
|
||||
定时任务支持三种调度类型:
|
||||
|
||||
- `at`:一次性时间戳(ISO 8601 字符串)。
|
||||
- `every`:固定间隔(毫秒)。
|
||||
- `cron`:5 字段 cron 表达式,可选 IANA 时区。
|
||||
|
||||
Cron 表达式使用 `croner`。如果省略时区,将使用 Gateway网关主机的本地时区。
|
||||
|
||||
### 主会话与隔离式执行
|
||||
|
||||
#### 主会话任务(系统事件)
|
||||
|
||||
主会话任务入队一个系统事件,并可选择唤醒心跳运行器。它们必须使用 `payload.kind = "systemEvent"`。
|
||||
|
||||
- `wakeMode: "next-heartbeat"`(默认):事件等待下一次计划心跳。
|
||||
- `wakeMode: "now"`:事件触发立即心跳运行。
|
||||
|
||||
当你需要正常的心跳提示 + 主会话上下文时,这是最佳选择。参见[心跳](/gateway/heartbeat)。
|
||||
|
||||
#### 隔离任务(专用定时会话)
|
||||
|
||||
隔离任务在会话 `cron:<jobId>` 中运行专用智能体轮次。
|
||||
|
||||
关键行为:
|
||||
|
||||
- 提示以 `[cron:<jobId> <任务名称>]` 为前缀,便于追踪。
|
||||
- 每次运行都会启动一个**全新的会话 ID**(不继承之前的对话)。
|
||||
- 如果未指定 `delivery`,隔离任务会默认以“announce”方式投递摘要。
|
||||
- `delivery.mode` 可选 `announce`(投递摘要)或 `none`(内部运行)。
|
||||
|
||||
对于嘈杂、频繁或"后台杂务"类任务,使用隔离任务可以避免污染你的主聊天记录。
|
||||
|
||||
### 负载结构(运行内容)
|
||||
|
||||
支持两种负载类型:
|
||||
|
||||
- `systemEvent`:仅限主会话,通过心跳提示路由。
|
||||
- `agentTurn`:仅限隔离会话,运行专用智能体轮次。
|
||||
|
||||
常用 `agentTurn` 字段:
|
||||
|
||||
- `message`:必填文本提示。
|
||||
- `model` / `thinking`:可选覆盖(见下文)。
|
||||
- `timeoutSeconds`:可选超时覆盖。
|
||||
|
||||
### 模型和思维覆盖
|
||||
|
||||
隔离任务(`agentTurn`)可以覆盖模型和思维级别:
|
||||
|
||||
- `model`:提供商/模型字符串(例如 `anthropic/claude-sonnet-4-20250514`)或别名(例如 `opus`)
|
||||
- `thinking`:思维级别(`off`、`minimal`、`low`、`medium`、`high`、`xhigh`;仅限 GPT-5.2 + Codex 模型)
|
||||
|
||||
注意:你也可以在主会话任务上设置 `model`,但这会更改共享的主会话模型。我们建议仅对隔离任务使用模型覆盖,以避免意外的上下文切换。
|
||||
|
||||
优先级解析顺序:
|
||||
|
||||
1. 任务负载覆盖(最高优先级)
|
||||
2. 钩子特定默认值(例如 `hooks.gmail.model`)
|
||||
3. 智能体配置默认值
|
||||
|
||||
### 投递(渠道 + 目标)
|
||||
|
||||
隔离任务可以通过顶层 `delivery` 配置投递输出:
|
||||
|
||||
- `delivery.mode`:`announce`(投递摘要)或 `none`
|
||||
- `delivery.channel`:`whatsapp` / `telegram` / `discord` / `slack` / `mattermost`(插件)/ `signal` / `imessage` / `last`
|
||||
- `delivery.to`:渠道特定的接收目标
|
||||
- `delivery.bestEffort`:投递失败时避免任务失败
|
||||
|
||||
当启用 announce 投递时,该轮次会抑制消息工具发送;请使用 `delivery.channel`/`delivery.to` 来指定目标。
|
||||
|
||||
如果省略 `delivery.channel` 或 `delivery.to`,定时任务会回退到主会话的“最后路由”(智能体最后回复的位置)。
|
||||
|
||||
目标格式提醒:
|
||||
|
||||
- Slack/Discord/Mattermost(插件)目标应使用明确前缀(例如 `channel:<id>`、`user:<id>`)以避免歧义。
|
||||
- Telegram 主题应使用 `:topic:` 格式(见下文)。
|
||||
|
||||
#### Telegram 投递目标(主题/论坛帖子)
|
||||
|
||||
Telegram 通过 `message_thread_id` 支持论坛主题。对于定时任务投递,你可以将主题/帖子编码到 `to` 字段中:
|
||||
|
||||
- `-1001234567890`(仅聊天 ID)
|
||||
- `-1001234567890:topic:123`(推荐:明确的主题标记)
|
||||
- `-1001234567890:123`(简写:数字后缀)
|
||||
|
||||
带前缀的目标如 `telegram:...` / `telegram:group:...` 也可接受:
|
||||
|
||||
- `telegram:group:-1001234567890:topic:123`
|
||||
|
||||
## 工具调用的 JSON 模式
|
||||
|
||||
直接调用 Gateway网关 `cron.*` 工具(智能体工具调用或 RPC)时使用这些结构。CLI 标志接受人类可读的时间格式如 `20m`,但工具调用应使用 ISO 8601 字符串作为 `schedule.at`,并使用毫秒作为 `schedule.everyMs`。
|
||||
|
||||
### cron.add 参数
|
||||
|
||||
一次性主会话任务(系统事件):
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Reminder",
|
||||
"schedule": { "kind": "at", "at": "2026-02-01T16:00:00Z" },
|
||||
"sessionTarget": "main",
|
||||
"wakeMode": "now",
|
||||
"payload": { "kind": "systemEvent", "text": "Reminder text" },
|
||||
"deleteAfterRun": true
|
||||
}
|
||||
```
|
||||
|
||||
带投递的周期性隔离任务:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Morning brief",
|
||||
"schedule": { "kind": "cron", "expr": "0 7 * * *", "tz": "America/Los_Angeles" },
|
||||
"sessionTarget": "isolated",
|
||||
"wakeMode": "next-heartbeat",
|
||||
"payload": {
|
||||
"kind": "agentTurn",
|
||||
"message": "Summarize overnight updates."
|
||||
},
|
||||
"delivery": {
|
||||
"mode": "announce",
|
||||
"channel": "slack",
|
||||
"to": "channel:C1234567890",
|
||||
"bestEffort": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `schedule.kind`:`at`(`at`)、`every`(`everyMs`)或 `cron`(`expr`,可选 `tz`)。
|
||||
- `schedule.at` 接受 ISO 8601(可省略时区;省略时按 UTC 处理)。
|
||||
- `everyMs` 为毫秒数。
|
||||
- `sessionTarget` 必须为 `"main"` 或 `"isolated"`,且必须与 `payload.kind` 匹配。
|
||||
- 可选字段:`agentId`、`description`、`enabled`、`deleteAfterRun`、`delivery`。
|
||||
- `wakeMode` 省略时默认为 `"next-heartbeat"`。
|
||||
|
||||
### cron.update 参数
|
||||
|
||||
```json
|
||||
{
|
||||
"jobId": "job-123",
|
||||
"patch": {
|
||||
"enabled": false,
|
||||
"schedule": { "kind": "every", "everyMs": 3600000 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `jobId` 是规范字段;`id` 可兼容使用。
|
||||
- 在补丁中使用 `agentId: null` 可清除智能体绑定。
|
||||
|
||||
### cron.run 和 cron.remove 参数
|
||||
|
||||
```json
|
||||
{ "jobId": "job-123", "mode": "force" }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "jobId": "job-123" }
|
||||
```
|
||||
|
||||
## 存储与历史
|
||||
|
||||
- 任务存储:`~/.openclaw/cron/jobs.json`(Gateway网关管理的 JSON)。
|
||||
- 运行历史:`~/.openclaw/cron/runs/<jobId>.jsonl`(JSONL,自动清理)。
|
||||
- 覆盖存储路径:配置中的 `cron.store`。
|
||||
|
||||
## 配置
|
||||
|
||||
```json5
|
||||
{
|
||||
cron: {
|
||||
enabled: true, // 默认 true
|
||||
store: "~/.openclaw/cron/jobs.json",
|
||||
maxConcurrentRuns: 1, // 默认 1
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
完全禁用定时任务:
|
||||
|
||||
- `cron.enabled: false`(配置)
|
||||
- `OPENCLAW_SKIP_CRON=1`(环境变量)
|
||||
|
||||
## CLI 快速开始
|
||||
|
||||
一次性提醒(UTC ISO,成功后自动删除):
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Send reminder" \
|
||||
--at "2026-01-12T18:00:00Z" \
|
||||
--session main \
|
||||
--system-event "Reminder: submit expense report." \
|
||||
--wake now \
|
||||
--delete-after-run
|
||||
```
|
||||
|
||||
一次性提醒(主会话,立即唤醒):
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Calendar check" \
|
||||
--at "20m" \
|
||||
--session main \
|
||||
--system-event "Next heartbeat: check calendar." \
|
||||
--wake now
|
||||
```
|
||||
|
||||
周期性隔离任务(投递到 WhatsApp):
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Morning status" \
|
||||
--cron "0 7 * * *" \
|
||||
--tz "America/Los_Angeles" \
|
||||
--session isolated \
|
||||
--message "Summarize inbox + calendar for today." \
|
||||
--announce \
|
||||
--channel whatsapp \
|
||||
--to "+15551234567"
|
||||
```
|
||||
|
||||
周期性隔离任务(投递到 Telegram 主题):
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Nightly summary (topic)" \
|
||||
--cron "0 22 * * *" \
|
||||
--tz "America/Los_Angeles" \
|
||||
--session isolated \
|
||||
--message "Summarize today; send to the nightly topic." \
|
||||
--announce \
|
||||
--channel telegram \
|
||||
--to "-1001234567890:topic:123"
|
||||
```
|
||||
|
||||
带模型和思维覆盖的隔离任务:
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Deep analysis" \
|
||||
--cron "0 6 * * 1" \
|
||||
--tz "America/Los_Angeles" \
|
||||
--session isolated \
|
||||
--message "Weekly deep analysis of project progress." \
|
||||
--model "opus" \
|
||||
--thinking high \
|
||||
--announce \
|
||||
--channel whatsapp \
|
||||
--to "+15551234567"
|
||||
```
|
||||
|
||||
智能体选择(多智能体配置):
|
||||
|
||||
```bash
|
||||
# 将任务绑定到智能体 "ops"(如果该智能体不存在则回退到默认智能体)
|
||||
openclaw cron add --name "Ops sweep" --cron "0 6 * * *" --session isolated --message "Check ops queue" --agent ops
|
||||
|
||||
# 切换或清除现有任务的智能体
|
||||
openclaw cron edit <jobId> --agent ops
|
||||
openclaw cron edit <jobId> --clear-agent
|
||||
```
|
||||
|
||||
手动运行(调试):
|
||||
|
||||
```bash
|
||||
openclaw cron run <jobId> --force
|
||||
```
|
||||
|
||||
编辑现有任务(补丁字段):
|
||||
|
||||
```bash
|
||||
openclaw cron edit <jobId> \
|
||||
--message "Updated prompt" \
|
||||
--model "opus" \
|
||||
--thinking low
|
||||
```
|
||||
|
||||
运行历史:
|
||||
|
||||
```bash
|
||||
openclaw cron runs --id <jobId> --limit 50
|
||||
```
|
||||
|
||||
不创建任务直接发送系统事件:
|
||||
|
||||
```bash
|
||||
openclaw system event --mode now --text "Next heartbeat: check battery."
|
||||
```
|
||||
|
||||
## Gateway网关 API 接口
|
||||
|
||||
- `cron.list`、`cron.status`、`cron.add`、`cron.update`、`cron.remove`
|
||||
- `cron.run`(强制或到期)、`cron.runs`
|
||||
如需不创建任务直接发送系统事件,请使用 [`openclaw system event`](/cli/system)。
|
||||
|
||||
## 故障排除
|
||||
|
||||
### "没有任何任务运行"
|
||||
|
||||
- 检查定时任务是否已启用:`cron.enabled` 和 `OPENCLAW_SKIP_CRON`。
|
||||
- 检查 Gateway网关是否持续运行(定时任务运行在 Gateway网关进程内部)。
|
||||
- 对于 `cron` 调度:确认时区(`--tz`)与主机时区的关系。
|
||||
|
||||
### Telegram 投递到了错误的位置
|
||||
|
||||
- 对于论坛主题,使用 `-100…:topic:<id>` 以确保明确无歧义。
|
||||
- 如果你在日志或存储的"最后路由"目标中看到 `telegram:...` 前缀,这是正常的;定时任务投递接受这些前缀并仍能正确解析主题 ID。
|
||||
286
content/automation/cron-vs-heartbeat.md
Normal file
286
content/automation/cron-vs-heartbeat.md
Normal file
@@ -0,0 +1,286 @@
|
||||
---
|
||||
read_when:
|
||||
- 决定如何调度周期性任务
|
||||
- 设置后台监控或通知
|
||||
- 优化定期检查的 token 用量
|
||||
summary: 选择心跳还是定时任务进行自动化的指南
|
||||
title: 定时任务与心跳对比
|
||||
x-i18n:
|
||||
generated_at: "2026-02-01T19:38:18Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 5f71a63181baa41b1c307eb7bfac561df7943d4627077dfa2861eb9f76ab086b
|
||||
source_path: automation/cron-vs-heartbeat.md
|
||||
workflow: 14
|
||||
---
|
||||
|
||||
# 定时任务与心跳:何时使用哪种方式
|
||||
|
||||
心跳和定时任务都可以按计划运行任务。本指南帮助你根据使用场景选择合适的机制。
|
||||
|
||||
## 快速决策指南
|
||||
|
||||
| 使用场景 | 推荐方式 | 原因 |
|
||||
| ------------------------- | -------------------------- | ---------------------------------------- |
|
||||
| 每 30 分钟检查收件箱 | 心跳 | 可与其他检查批量处理,具备上下文感知能力 |
|
||||
| 每天上午 9 点准时发送报告 | 定时任务(隔离式) | 需要精确定时 |
|
||||
| 监控日历中即将到来的事件 | 心跳 | 天然适合周期性感知 |
|
||||
| 运行每周深度分析 | 定时任务(隔离式) | 独立任务,可使用不同模型 |
|
||||
| 20 分钟后提醒我 | 定时任务(主会话,`--at`) | 精确定时的一次性任务 |
|
||||
| 后台项目健康检查 | 心跳 | 搭载在现有周期上 |
|
||||
|
||||
## 心跳:周期性感知
|
||||
|
||||
心跳在**主会话**中以固定间隔运行(默认:30 分钟)。它的设计目的是让智能体检查各种事项并呈现重要信息。
|
||||
|
||||
### 何时使用心跳
|
||||
|
||||
- **多个周期性检查**:与其设置 5 个独立的定时任务分别检查收件箱、日历、天气、通知和项目状态,不如用一次心跳批量处理所有内容。
|
||||
- **上下文感知决策**:智能体拥有完整的主会话上下文,因此可以智能判断哪些紧急、哪些可以等待。
|
||||
- **对话连续性**:心跳运行共享同一会话,因此智能体记得最近的对话,可以自然地进行后续跟进。
|
||||
- **低开销监控**:一次心跳替代多个小型轮询任务。
|
||||
|
||||
### 心跳优势
|
||||
|
||||
- **批量处理多项检查**:一次智能体轮次可以同时审查收件箱、日历和通知。
|
||||
- **减少 API 调用**:一次心跳比 5 个隔离式定时任务更经济。
|
||||
- **上下文感知**:智能体了解你一直在做什么,可以据此排定优先级。
|
||||
- **智能抑制**:如果没有需要关注的事项,智能体回复 `HEARTBEAT_OK`,不会投递任何消息。
|
||||
- **自然定时**:会根据队列负载略有漂移,但对大多数监控来说没有问题。
|
||||
|
||||
### 心跳示例:HEARTBEAT.md 检查清单
|
||||
|
||||
```md
|
||||
# Heartbeat checklist
|
||||
|
||||
- Check email for urgent messages
|
||||
- Review calendar for events in next 2 hours
|
||||
- If a background task finished, summarize results
|
||||
- If idle for 8+ hours, send a brief check-in
|
||||
```
|
||||
|
||||
智能体在每次心跳时读取此清单,并在一次轮次中处理所有项目。
|
||||
|
||||
### 配置心跳
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
heartbeat: {
|
||||
every: "30m", // 间隔
|
||||
target: "last", // 告警投递目标
|
||||
activeHours: { start: "08:00", end: "22:00" }, // 可选
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
完整配置请参阅[心跳](/gateway/heartbeat)。
|
||||
|
||||
## 定时任务:精确调度
|
||||
|
||||
定时任务在**精确时间**运行,可以在隔离会话中运行而不影响主会话上下文。
|
||||
|
||||
### 何时使用定时任务
|
||||
|
||||
- **需要精确定时**:"每周一上午 9:00 发送"(而不是"大约 9 点左右")。
|
||||
- **独立任务**:不需要对话上下文的任务。
|
||||
- **不同的模型/思维级别**:需要更强大模型的深度分析。
|
||||
- **一次性提醒**:使用 `--at` 实现"20 分钟后提醒我"。
|
||||
- **嘈杂/频繁的任务**:会把主会话历史搞得杂乱的任务。
|
||||
- **外部触发器**:无论智能体是否处于活跃状态都应独立运行的任务。
|
||||
|
||||
### 定时任务优势
|
||||
|
||||
- **精确定时**:支持带时区的 5 字段 cron 表达式。
|
||||
- **会话隔离**:在 `cron:<jobId>` 中运行,不会污染主会话历史。
|
||||
- **模型覆盖**:可按任务使用更便宜或更强大的模型。
|
||||
- **投递控制**:隔离任务默认以 `announce` 投递摘要,可选 `none` 仅内部运行。
|
||||
- **无需智能体上下文**:即使主会话空闲或已压缩,也能运行。
|
||||
- **一次性支持**:`--at` 用于精确的未来时间戳。
|
||||
|
||||
### 定时任务示例:每日早间简报
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Morning briefing" \
|
||||
--cron "0 7 * * *" \
|
||||
--tz "America/New_York" \
|
||||
--session isolated \
|
||||
--message "Generate today's briefing: weather, calendar, top emails, news summary." \
|
||||
--model opus \
|
||||
--announce \
|
||||
--channel whatsapp \
|
||||
--to "+15551234567"
|
||||
```
|
||||
|
||||
这会在纽约时间每天早上 7:00 准时运行,使用 Opus 保证质量,并直接投递到 WhatsApp。
|
||||
|
||||
### 定时任务示例:一次性提醒
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Meeting reminder" \
|
||||
--at "20m" \
|
||||
--session main \
|
||||
--system-event "Reminder: standup meeting starts in 10 minutes." \
|
||||
--wake now \
|
||||
--delete-after-run
|
||||
```
|
||||
|
||||
完整 CLI 参考请参阅[定时任务](/automation/cron-jobs)。
|
||||
|
||||
## 决策流程图
|
||||
|
||||
```
|
||||
任务是否需要在精确时间运行?
|
||||
是 -> 使用定时任务
|
||||
否 -> 继续...
|
||||
|
||||
任务是否需要与主会话隔离?
|
||||
是 -> 使用定时任务(隔离式)
|
||||
否 -> 继续...
|
||||
|
||||
此任务能否与其他周期性检查批量处理?
|
||||
是 -> 使用心跳(添加到 HEARTBEAT.md)
|
||||
否 -> 使用定时任务
|
||||
|
||||
这是一次性提醒吗?
|
||||
是 -> 使用定时任务配合 --at
|
||||
否 -> 继续...
|
||||
|
||||
是否需要不同的模型或思维级别?
|
||||
是 -> 使用定时任务(隔离式)配合 --model/--thinking
|
||||
否 -> 使用心跳
|
||||
```
|
||||
|
||||
## 组合使用
|
||||
|
||||
最高效的配置是**两者结合**:
|
||||
|
||||
1. **心跳**处理常规监控(收件箱、日历、通知),每 30 分钟批量处理一次。
|
||||
2. **定时任务**处理精确调度(每日报告、每周回顾)和一次性提醒。
|
||||
|
||||
### 示例:高效自动化配置
|
||||
|
||||
**HEARTBEAT.md**(每 30 分钟检查一次):
|
||||
|
||||
```md
|
||||
# Heartbeat checklist
|
||||
|
||||
- Scan inbox for urgent emails
|
||||
- Check calendar for events in next 2h
|
||||
- Review any pending tasks
|
||||
- Light check-in if quiet for 8+ hours
|
||||
```
|
||||
|
||||
**定时任务**(精确定时):
|
||||
|
||||
```bash
|
||||
# 每天早上 7 点的早间简报
|
||||
openclaw cron add --name "Morning brief" --cron "0 7 * * *" --session isolated --message "..." --announce
|
||||
|
||||
# 每周一上午 9 点的项目回顾
|
||||
openclaw cron add --name "Weekly review" --cron "0 9 * * 1" --session isolated --message "..." --model opus
|
||||
|
||||
# 一次性提醒
|
||||
openclaw cron add --name "Call back" --at "2h" --session main --system-event "Call back the client" --wake now
|
||||
```
|
||||
|
||||
## Lobster:带审批的确定性工作流
|
||||
|
||||
Lobster 是用于**多步骤工具管道**的工作流运行时,适用于需要确定性执行和明确审批的场景。当任务不只是单次智能体轮次,且你需要可恢复的带人工检查点的工作流时,使用它。
|
||||
|
||||
### 何时适合使用 Lobster
|
||||
|
||||
- **多步骤自动化**:你需要一个固定的工具调用管道,而不是一次性提示。
|
||||
- **审批关卡**:副作用应暂停直到你批准,然后继续执行。
|
||||
- **可恢复运行**:继续暂停的工作流而无需重新运行之前的步骤。
|
||||
|
||||
### 如何与心跳和定时任务配合
|
||||
|
||||
- **心跳/定时任务**决定*何时*运行。
|
||||
- **Lobster** 定义运行开始后*执行哪些步骤*。
|
||||
|
||||
对于计划性工作流,使用定时任务或心跳触发一次调用 Lobster 的智能体轮次。对于临时工作流,直接调用 Lobster。
|
||||
|
||||
### 操作说明(来自代码)
|
||||
|
||||
- Lobster 以**本地子进程**(`lobster` CLI)在工具模式下运行,并返回 **JSON 信封**。
|
||||
- 如果工具返回 `needs_approval`,你需要使用 `resumeToken` 和 `approve` 标志来恢复。
|
||||
- 该工具是**可选插件**;建议通过 `tools.alsoAllow: ["lobster"]` 附加启用。
|
||||
- 如果传入 `lobsterPath`,必须是**绝对路径**。
|
||||
|
||||
完整用法和示例请参阅 [Lobster](/tools/lobster)。
|
||||
|
||||
## 主会话与隔离会话
|
||||
|
||||
心跳和定时任务都可以与主会话交互,但方式不同:
|
||||
|
||||
| | 心跳 | 定时任务(主会话) | 定时任务(隔离式) |
|
||||
| ------ | ------------------------ | ---------------------- | --------------------- |
|
||||
| 会话 | 主会话 | 主会话(通过系统事件) | `cron:<jobId>` |
|
||||
| 历史 | 共享 | 共享 | 每次运行全新 |
|
||||
| 上下文 | 完整 | 完整 | 无(从零开始) |
|
||||
| 模型 | 主会话模型 | 主会话模型 | 可覆盖 |
|
||||
| 输出 | 非 `HEARTBEAT_OK` 时投递 | 心跳提示 + 事件 | announce 摘要(默认) |
|
||||
|
||||
### 何时使用主会话定时任务
|
||||
|
||||
当你需要以下场景时,使用 `--session main` 配合 `--system-event`:
|
||||
|
||||
- 提醒/事件出现在主会话上下文中
|
||||
- 智能体在下一次心跳时带着完整上下文处理它
|
||||
- 不需要单独的隔离运行
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Check project" \
|
||||
--every "4h" \
|
||||
--session main \
|
||||
--system-event "Time for a project health check" \
|
||||
--wake now
|
||||
```
|
||||
|
||||
### 何时使用隔离式定时任务
|
||||
|
||||
当你需要以下场景时,使用 `--session isolated`:
|
||||
|
||||
- 无先前上下文的全新环境
|
||||
- 不同的模型或思维设置
|
||||
- 输出可通过 `announce` 直接投递摘要(或用 `none` 仅内部运行)
|
||||
- 不会把主会话搞得杂乱的历史记录
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Deep analysis" \
|
||||
--cron "0 6 * * 0" \
|
||||
--session isolated \
|
||||
--message "Weekly codebase analysis..." \
|
||||
--model opus \
|
||||
--thinking high \
|
||||
--announce
|
||||
```
|
||||
|
||||
## 成本考量
|
||||
|
||||
| 机制 | 成本特征 |
|
||||
| ------------------ | ---------------------------------------------- |
|
||||
| 心跳 | 每 N 分钟一次轮次;随 HEARTBEAT.md 大小扩展 |
|
||||
| 定时任务(主会话) | 将事件添加到下一次心跳(无隔离轮次) |
|
||||
| 定时任务(隔离式) | 每个任务一次完整智能体轮次;可使用更便宜的模型 |
|
||||
|
||||
**建议**:
|
||||
|
||||
- 保持 `HEARTBEAT.md` 精简以减少 token 开销。
|
||||
- 将类似的检查批量放入心跳,而不是创建多个定时任务。
|
||||
- 如果只需要内部处理,在心跳上使用 `target: "none"`。
|
||||
- 对常规任务使用隔离式定时任务配合更便宜的模型。
|
||||
|
||||
## 相关内容
|
||||
|
||||
- [心跳](/gateway/heartbeat) - 完整的心跳配置
|
||||
- [定时任务](/automation/cron-jobs) - 完整的定时任务 CLI 和 API 参考
|
||||
- [系统](/cli/system) - 系统事件 + 心跳控制
|
||||
249
content/automation/gmail-pubsub.md
Normal file
249
content/automation/gmail-pubsub.md
Normal file
@@ -0,0 +1,249 @@
|
||||
---
|
||||
read_when:
|
||||
- 将 Gmail 收件箱触发器接入 OpenClaw
|
||||
- 为智能体唤醒设置 Pub/Sub 推送
|
||||
summary: 通过 gogcli 将 Gmail Pub/Sub 推送接入 OpenClaw webhooks
|
||||
title: Gmail PubSub
|
||||
x-i18n:
|
||||
generated_at: "2026-02-03T07:43:25Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: dfb92133b69177e4e984b7d072f5dc28aa53a9e0cf984a018145ed811aa96195
|
||||
source_path: automation/gmail-pubsub.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# Gmail Pub/Sub -> OpenClaw
|
||||
|
||||
目标:Gmail watch -> Pub/Sub 推送 -> `gog gmail watch serve` -> OpenClaw webhook。
|
||||
|
||||
## 前置条件
|
||||
|
||||
- 已安装并登录 `gcloud`([安装指南](https://docs.cloud.google.com/sdk/docs/install-sdk))。
|
||||
- 已安装 `gog` (gogcli) 并为 Gmail 账户授权([gogcli.sh](https://gogcli.sh/))。
|
||||
- 已启用 OpenClaw hooks(参见 [Webhooks](/automation/webhook))。
|
||||
- 已登录 `tailscale`([tailscale.com](https://tailscale.com/))。支持的设置使用 Tailscale Funnel 作为公共 HTTPS 端点。
|
||||
其他隧道服务也可以使用,但需要自行配置/不受支持,需要手动接入。
|
||||
目前,我们支持的是 Tailscale。
|
||||
|
||||
示例 hook 配置(启用 Gmail 预设映射):
|
||||
|
||||
```json5
|
||||
{
|
||||
hooks: {
|
||||
enabled: true,
|
||||
token: "OPENCLAW_HOOK_TOKEN",
|
||||
path: "/hooks",
|
||||
presets: ["gmail"],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
要将 Gmail 摘要投递到聊天界面,请用设置了 `deliver` 以及可选的 `channel`/`to` 的映射覆盖预设:
|
||||
|
||||
```json5
|
||||
{
|
||||
hooks: {
|
||||
enabled: true,
|
||||
token: "OPENCLAW_HOOK_TOKEN",
|
||||
presets: ["gmail"],
|
||||
mappings: [
|
||||
{
|
||||
match: { path: "gmail" },
|
||||
action: "agent",
|
||||
wakeMode: "now",
|
||||
name: "Gmail",
|
||||
sessionKey: "hook:gmail:{{messages[0].id}}",
|
||||
messageTemplate: "New email from {{messages[0].from}}\nSubject: {{messages[0].subject}}\n{{messages[0].snippet}}\n{{messages[0].body}}",
|
||||
model: "openai/gpt-5.2-mini",
|
||||
deliver: true,
|
||||
channel: "last",
|
||||
// to: "+15551234567"
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
如果你想使用固定渠道,请设置 `channel` + `to`。否则 `channel: "last"` 会使用上次的投递路由(默认回退到 WhatsApp)。
|
||||
|
||||
要为 Gmail 运行强制使用更便宜的模型,请在映射中设置 `model`(`provider/model` 或别名)。如果你强制启用了 `agents.defaults.models`,请将其包含在内。
|
||||
|
||||
要专门为 Gmail hooks 设置默认模型和思考级别,请在配置中添加 `hooks.gmail.model` / `hooks.gmail.thinking`:
|
||||
|
||||
```json5
|
||||
{
|
||||
hooks: {
|
||||
gmail: {
|
||||
model: "openrouter/meta-llama/llama-3.3-70b-instruct:free",
|
||||
thinking: "off",
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
注意事项:
|
||||
|
||||
- 映射中的每个 hook 的 `model`/`thinking` 仍会覆盖这些默认值。
|
||||
- 回退顺序:`hooks.gmail.model` → `agents.defaults.model.fallbacks` → 主模型(认证/速率限制/超时)。
|
||||
- 如果设置了 `agents.defaults.models`,Gmail 模型必须在允许列表中。
|
||||
- Gmail hook 内容默认使用外部内容安全边界包装。
|
||||
要禁用(危险),请设置 `hooks.gmail.allowUnsafeExternalContent: true`。
|
||||
|
||||
要进一步自定义负载处理,请添加 `hooks.mappings` 或在 `hooks.transformsDir` 下添加 JS/TS 转换模块(参见 [Webhooks](/automation/webhook))。
|
||||
|
||||
## 向导(推荐)
|
||||
|
||||
使用 OpenClaw 助手将所有内容接入在一起(在 macOS 上通过 brew 安装依赖):
|
||||
|
||||
```bash
|
||||
openclaw webhooks gmail setup \
|
||||
--account openclaw@gmail.com
|
||||
```
|
||||
|
||||
默认设置:
|
||||
|
||||
- 使用 Tailscale Funnel 作为公共推送端点。
|
||||
- 为 `openclaw webhooks gmail run` 写入 `hooks.gmail` 配置。
|
||||
- 启用 Gmail hook 预设(`hooks.presets: ["gmail"]`)。
|
||||
|
||||
路径说明:当启用 `tailscale.mode` 时,OpenClaw 会自动将 `hooks.gmail.serve.path` 设置为 `/`,并将公共路径保持在 `hooks.gmail.tailscale.path`(默认 `/gmail-pubsub`),因为 Tailscale 在代理之前会剥离设置的路径前缀。
|
||||
如果你需要后端接收带前缀的路径,请将 `hooks.gmail.tailscale.target`(或 `--tailscale-target`)设置为完整 URL,如 `http://127.0.0.1:8788/gmail-pubsub`,并匹配 `hooks.gmail.serve.path`。
|
||||
|
||||
想要自定义端点?使用 `--push-endpoint <url>` 或 `--tailscale off`。
|
||||
|
||||
平台说明:在 macOS 上,向导通过 Homebrew 安装 `gcloud`、`gogcli` 和 `tailscale`;在 Linux 上请先手动安装它们。
|
||||
|
||||
Gateway 网关自动启动(推荐):
|
||||
|
||||
- 当 `hooks.enabled=true` 且设置了 `hooks.gmail.account` 时,Gateway 网关会在启动时运行 `gog gmail watch serve` 并自动续期 watch。
|
||||
- 设置 `OPENCLAW_SKIP_GMAIL_WATCHER=1` 可退出(如果你自己运行守护进程则很有用)。
|
||||
- 不要同时运行手动守护进程,否则会遇到 `listen tcp 127.0.0.1:8788: bind: address already in use`。
|
||||
|
||||
手动守护进程(启动 `gog gmail watch serve` + 自动续期):
|
||||
|
||||
```bash
|
||||
openclaw webhooks gmail run
|
||||
```
|
||||
|
||||
## 一次性设置
|
||||
|
||||
1. 选择**拥有 `gog` 使用的 OAuth 客户端**的 GCP 项目。
|
||||
|
||||
```bash
|
||||
gcloud auth login
|
||||
gcloud config set project <project-id>
|
||||
```
|
||||
|
||||
注意:Gmail watch 要求 Pub/Sub 主题与 OAuth 客户端位于同一项目中。
|
||||
|
||||
2. 启用 API:
|
||||
|
||||
```bash
|
||||
gcloud services enable gmail.googleapis.com pubsub.googleapis.com
|
||||
```
|
||||
|
||||
3. 创建主题:
|
||||
|
||||
```bash
|
||||
gcloud pubsub topics create gog-gmail-watch
|
||||
```
|
||||
|
||||
4. 允许 Gmail push 发布:
|
||||
|
||||
```bash
|
||||
gcloud pubsub topics add-iam-policy-binding gog-gmail-watch \
|
||||
--member=serviceAccount:gmail-api-push@system.gserviceaccount.com \
|
||||
--role=roles/pubsub.publisher
|
||||
```
|
||||
|
||||
## 启动 watch
|
||||
|
||||
```bash
|
||||
gog gmail watch start \
|
||||
--account openclaw@gmail.com \
|
||||
--label INBOX \
|
||||
--topic projects/<project-id>/topics/gog-gmail-watch
|
||||
```
|
||||
|
||||
保存输出中的 `history_id`(用于调试)。
|
||||
|
||||
## 运行推送处理程序
|
||||
|
||||
本地示例(共享 token 认证):
|
||||
|
||||
```bash
|
||||
gog gmail watch serve \
|
||||
--account openclaw@gmail.com \
|
||||
--bind 127.0.0.1 \
|
||||
--port 8788 \
|
||||
--path /gmail-pubsub \
|
||||
--token <shared> \
|
||||
--hook-url http://127.0.0.1:18789/hooks/gmail \
|
||||
--hook-token OPENCLAW_HOOK_TOKEN \
|
||||
--include-body \
|
||||
--max-bytes 20000
|
||||
```
|
||||
|
||||
注意事项:
|
||||
|
||||
- `--token` 保护推送端点(`x-gog-token` 或 `?token=`)。
|
||||
- `--hook-url` 指向 OpenClaw `/hooks/gmail`(已映射;隔离运行 + 摘要发送到主线程)。
|
||||
- `--include-body` 和 `--max-bytes` 控制发送到 OpenClaw 的正文片段。
|
||||
|
||||
推荐:`openclaw webhooks gmail run` 封装了相同的流程并自动续期 watch。
|
||||
|
||||
## 暴露处理程序(高级,不受支持)
|
||||
|
||||
如果你需要非 Tailscale 隧道,请手动接入并在推送订阅中使用公共 URL(不受支持,无保护措施):
|
||||
|
||||
```bash
|
||||
cloudflared tunnel --url http://127.0.0.1:8788 --no-autoupdate
|
||||
```
|
||||
|
||||
使用生成的 URL 作为推送端点:
|
||||
|
||||
```bash
|
||||
gcloud pubsub subscriptions create gog-gmail-watch-push \
|
||||
--topic gog-gmail-watch \
|
||||
--push-endpoint "https://<public-url>/gmail-pubsub?token=<shared>"
|
||||
```
|
||||
|
||||
生产环境:使用稳定的 HTTPS 端点并配置 Pub/Sub OIDC JWT,然后运行:
|
||||
|
||||
```bash
|
||||
gog gmail watch serve --verify-oidc --oidc-email <svc@...>
|
||||
```
|
||||
|
||||
## 测试
|
||||
|
||||
向被监视的收件箱发送一条消息:
|
||||
|
||||
```bash
|
||||
gog gmail send \
|
||||
--account openclaw@gmail.com \
|
||||
--to openclaw@gmail.com \
|
||||
--subject "watch test" \
|
||||
--body "ping"
|
||||
```
|
||||
|
||||
检查 watch 状态和历史记录:
|
||||
|
||||
```bash
|
||||
gog gmail watch status --account openclaw@gmail.com
|
||||
gog gmail history --account openclaw@gmail.com --since <historyId>
|
||||
```
|
||||
|
||||
## 故障排除
|
||||
|
||||
- `Invalid topicName`:项目不匹配(主题不在 OAuth 客户端项目中)。
|
||||
- `User not authorized`:主题缺少 `roles/pubsub.publisher`。
|
||||
- 空消息:Gmail push 仅提供 `historyId`;通过 `gog gmail history` 获取。
|
||||
|
||||
## 清理
|
||||
|
||||
```bash
|
||||
gog gmail watch stop --account openclaw@gmail.com
|
||||
gcloud pubsub subscriptions delete gog-gmail-watch-push
|
||||
gcloud pubsub topics delete gog-gmail-watch
|
||||
```
|
||||
882
content/automation/hooks.md
Normal file
882
content/automation/hooks.md
Normal file
@@ -0,0 +1,882 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想为 /new、/reset、/stop 和智能体生命周期事件实现事件驱动自动化
|
||||
- 你想构建、安装或调试 hooks
|
||||
summary: Hooks:用于命令和生命周期事件的事件驱动自动化
|
||||
title: Hooks
|
||||
x-i18n:
|
||||
generated_at: "2026-02-03T07:50:59Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 853227a0f1abd20790b425fa64dda60efc6b5f93c1b13ecd2dcb788268f71d79
|
||||
source_path: automation/hooks.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# Hooks
|
||||
|
||||
Hooks 提供了一个可扩展的事件驱动系统,用于响应智能体命令和事件自动执行操作。Hooks 从目录中自动发现,可以通过 CLI 命令管理,类似于 OpenClaw 中 Skills 的工作方式。
|
||||
|
||||
## 入门指南
|
||||
|
||||
Hooks 是在事件发生时运行的小脚本。有两种类型:
|
||||
|
||||
- **Hooks**(本页):当智能体事件触发时在 Gateway 网关内运行,如 `/new`、`/reset`、`/stop` 或生命周期事件。
|
||||
- **Webhooks**:外部 HTTP webhooks,让其他系统触发 OpenClaw 中的工作。参见 [Webhook Hooks](/automation/webhook) 或使用 `openclaw webhooks` 获取 Gmail 助手命令。
|
||||
|
||||
Hooks 也可以捆绑在插件中;参见 [插件](/tools/plugin#plugin-hooks)。
|
||||
|
||||
常见用途:
|
||||
|
||||
- 重置会话时保存记忆快照
|
||||
- 保留命令审计跟踪用于故障排除或合规
|
||||
- 会话开始或结束时触发后续自动化
|
||||
- 事件触发时向智能体工作区写入文件或调用外部 API
|
||||
|
||||
如果你能写一个小的 TypeScript 函数,你就能写一个 hook。Hooks 会自动发现,你可以通过 CLI 启用或禁用它们。
|
||||
|
||||
## 概述
|
||||
|
||||
hooks 系统允许你:
|
||||
|
||||
- 在发出 `/new` 时将会话上下文保存到记忆
|
||||
- 记录所有命令以供审计
|
||||
- 在智能体生命周期事件上触发自定义自动化
|
||||
- 在不修改核心代码的情况下扩展 OpenClaw 的行为
|
||||
|
||||
## 入门
|
||||
|
||||
### 捆绑的 Hooks
|
||||
|
||||
OpenClaw 附带三个自动发现的捆绑 hooks:
|
||||
|
||||
- **💾 session-memory**:当你发出 `/new` 时将会话上下文保存到智能体工作区(默认 `~/.openclaw/workspace/memory/`)
|
||||
- **📝 command-logger**:将所有命令事件记录到 `~/.openclaw/logs/commands.log`
|
||||
- **🚀 boot-md**:当 Gateway 网关启动时运行 `BOOT.md`(需要启用内部 hooks)
|
||||
|
||||
列出可用的 hooks:
|
||||
|
||||
```bash
|
||||
openclaw hooks list
|
||||
```
|
||||
|
||||
启用一个 hook:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable session-memory
|
||||
```
|
||||
|
||||
检查 hook 状态:
|
||||
|
||||
```bash
|
||||
openclaw hooks check
|
||||
```
|
||||
|
||||
获取详细信息:
|
||||
|
||||
```bash
|
||||
openclaw hooks info session-memory
|
||||
```
|
||||
|
||||
### 新手引导
|
||||
|
||||
在新手引导期间(`openclaw onboard`),你将被提示启用推荐的 hooks。向导会自动发现符合条件的 hooks 并呈现供选择。
|
||||
|
||||
## Hook 发现
|
||||
|
||||
Hooks 从三个目录自动发现(按优先级顺序):
|
||||
|
||||
1. **工作区 hooks**:`<workspace>/hooks/`(每智能体,最高优先级)
|
||||
2. **托管 hooks**:`~/.openclaw/hooks/`(用户安装,跨工作区共享)
|
||||
3. **捆绑 hooks**:`<openclaw>/dist/hooks/bundled/`(随 OpenClaw 附带)
|
||||
|
||||
托管 hook 目录可以是**单个 hook** 或 **hook 包**(包目录)。
|
||||
|
||||
每个 hook 是一个包含以下内容的目录:
|
||||
|
||||
```
|
||||
my-hook/
|
||||
├── HOOK.md # 元数据 + 文档
|
||||
└── handler.ts # 处理程序实现
|
||||
```
|
||||
|
||||
## Hook 包(npm/archives)
|
||||
|
||||
Hook 包是标准的 npm 包,通过 `package.json` 中的 `openclaw.hooks` 导出一个或多个 hooks。使用以下命令安装:
|
||||
|
||||
```bash
|
||||
openclaw hooks install <path-or-spec>
|
||||
```
|
||||
|
||||
示例 `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@acme/my-hooks",
|
||||
"version": "0.1.0",
|
||||
"openclaw": {
|
||||
"hooks": ["./hooks/my-hook", "./hooks/other-hook"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
每个条目指向包含 `HOOK.md` 和 `handler.ts`(或 `index.ts`)的 hook 目录。
|
||||
Hook 包可以附带依赖;它们将安装在 `~/.openclaw/hooks/<id>` 下。
|
||||
|
||||
## Hook 结构
|
||||
|
||||
### HOOK.md 格式
|
||||
|
||||
`HOOK.md` 文件在 YAML frontmatter 中包含元数据,加上 Markdown 文档:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: my-hook
|
||||
description: "Short description of what this hook does"
|
||||
homepage: https://docs.openclaw.ai/automation/hooks#my-hook
|
||||
metadata:
|
||||
{ "openclaw": { "emoji": "🔗", "events": ["command:new"], "requires": { "bins": ["node"] } } }
|
||||
---
|
||||
|
||||
# My Hook
|
||||
|
||||
Detailed documentation goes here...
|
||||
|
||||
## What It Does
|
||||
|
||||
- Listens for `/new` commands
|
||||
- Performs some action
|
||||
- Logs the result
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js must be installed
|
||||
|
||||
## Configuration
|
||||
|
||||
No configuration needed.
|
||||
```
|
||||
|
||||
### 元数据字段
|
||||
|
||||
`metadata.openclaw` 对象支持:
|
||||
|
||||
- **`emoji`**:CLI 的显示表情符号(例如 `"💾"`)
|
||||
- **`events`**:要监听的事件数组(例如 `["command:new", "command:reset"]`)
|
||||
- **`export`**:要使用的命名导出(默认为 `"default"`)
|
||||
- **`homepage`**:文档 URL
|
||||
- **`requires`**:可选要求
|
||||
- **`bins`**:PATH 中需要的二进制文件(例如 `["git", "node"]`)
|
||||
- **`anyBins`**:这些二进制文件中至少有一个必须存在
|
||||
- **`env`**:需要的环境变量
|
||||
- **`config`**:需要的配置路径(例如 `["workspace.dir"]`)
|
||||
- **`os`**:需要的平台(例如 `["darwin", "linux"]`)
|
||||
- **`always`**:绕过资格检查(布尔值)
|
||||
- **`install`**:安装方法(对于捆绑 hooks:`[{"id":"bundled","kind":"bundled"}]`)
|
||||
|
||||
### 处理程序实现
|
||||
|
||||
`handler.ts` 文件导出一个 `HookHandler` 函数:
|
||||
|
||||
```typescript
|
||||
import type { HookHandler } from "../../src/hooks/hooks.js";
|
||||
|
||||
const myHandler: HookHandler = async (event) => {
|
||||
// Only trigger on 'new' command
|
||||
if (event.type !== "command" || event.action !== "new") {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[my-hook] New command triggered`);
|
||||
console.log(` Session: ${event.sessionKey}`);
|
||||
console.log(` Timestamp: ${event.timestamp.toISOString()}`);
|
||||
|
||||
// Your custom logic here
|
||||
|
||||
// Optionally send message to user
|
||||
event.messages.push("✨ My hook executed!");
|
||||
};
|
||||
|
||||
export default myHandler;
|
||||
```
|
||||
|
||||
#### 事件上下文
|
||||
|
||||
每个事件包含:
|
||||
|
||||
```typescript
|
||||
{
|
||||
type: 'command' | 'session' | 'agent' | 'gateway',
|
||||
action: string, // e.g., 'new', 'reset', 'stop'
|
||||
sessionKey: string, // Session identifier
|
||||
timestamp: Date, // When the event occurred
|
||||
messages: string[], // Push messages here to send to user
|
||||
context: {
|
||||
sessionEntry?: SessionEntry,
|
||||
sessionId?: string,
|
||||
sessionFile?: string,
|
||||
commandSource?: string, // e.g., 'whatsapp', 'telegram'
|
||||
senderId?: string,
|
||||
workspaceDir?: string,
|
||||
bootstrapFiles?: WorkspaceBootstrapFile[],
|
||||
cfg?: OpenClawConfig
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 事件类型
|
||||
|
||||
### 命令事件
|
||||
|
||||
当发出智能体命令时触发:
|
||||
|
||||
- **`command`**:所有命令事件(通用监听器)
|
||||
- **`command:new`**:当发出 `/new` 命令时
|
||||
- **`command:reset`**:当发出 `/reset` 命令时
|
||||
- **`command:stop`**:当发出 `/stop` 命令时
|
||||
|
||||
### 智能体事件
|
||||
|
||||
- **`agent:bootstrap`**:在注入工作区引导文件之前(hooks 可以修改 `context.bootstrapFiles`)
|
||||
|
||||
### Gateway 网关事件
|
||||
|
||||
当 Gateway 网关启动时触发:
|
||||
|
||||
- **`gateway:startup`**:在渠道启动和 hooks 加载之后
|
||||
|
||||
### 工具结果 Hooks(插件 API)
|
||||
|
||||
这些 hooks 不是事件流监听器;它们让插件在 OpenClaw 持久化工具结果之前同步调整它们。
|
||||
|
||||
- **`tool_result_persist`**:在工具结果写入会话记录之前转换它们。必须是同步的;返回更新后的工具结果负载或 `undefined` 保持原样。参见 [智能体循环](/concepts/agent-loop)。
|
||||
|
||||
### 未来事件
|
||||
|
||||
计划中的事件类型:
|
||||
|
||||
- **`session:start`**:当新会话开始时
|
||||
- **`session:end`**:当会话结束时
|
||||
- **`agent:error`**:当智能体遇到错误时
|
||||
- **`message:sent`**:当消息被发送时
|
||||
- **`message:received`**:当消息被接收时
|
||||
|
||||
## 创建自定义 Hooks
|
||||
|
||||
### 1. 选择位置
|
||||
|
||||
- **工作区 hooks**(`<workspace>/hooks/`):每智能体,最高优先级
|
||||
- **托管 hooks**(`~/.openclaw/hooks/`):跨工作区共享
|
||||
|
||||
### 2. 创建目录结构
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/hooks/my-hook
|
||||
cd ~/.openclaw/hooks/my-hook
|
||||
```
|
||||
|
||||
### 3. 创建 HOOK.md
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: my-hook
|
||||
description: "Does something useful"
|
||||
metadata: { "openclaw": { "emoji": "🎯", "events": ["command:new"] } }
|
||||
---
|
||||
|
||||
# My Custom Hook
|
||||
|
||||
This hook does something useful when you issue `/new`.
|
||||
```
|
||||
|
||||
### 4. 创建 handler.ts
|
||||
|
||||
```typescript
|
||||
import type { HookHandler } from "../../src/hooks/hooks.js";
|
||||
|
||||
const handler: HookHandler = async (event) => {
|
||||
if (event.type !== "command" || event.action !== "new") {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("[my-hook] Running!");
|
||||
// Your logic here
|
||||
};
|
||||
|
||||
export default handler;
|
||||
```
|
||||
|
||||
### 5. 启用并测试
|
||||
|
||||
```bash
|
||||
# Verify hook is discovered
|
||||
openclaw hooks list
|
||||
|
||||
# Enable it
|
||||
openclaw hooks enable my-hook
|
||||
|
||||
# Restart your gateway process (menu bar app restart on macOS, or restart your dev process)
|
||||
|
||||
# Trigger the event
|
||||
# Send /new via your messaging channel
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
### 新配置格式(推荐)
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"internal": {
|
||||
"enabled": true,
|
||||
"entries": {
|
||||
"session-memory": { "enabled": true },
|
||||
"command-logger": { "enabled": false }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 每 Hook 配置
|
||||
|
||||
Hooks 可以有自定义配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"internal": {
|
||||
"enabled": true,
|
||||
"entries": {
|
||||
"my-hook": {
|
||||
"enabled": true,
|
||||
"env": {
|
||||
"MY_CUSTOM_VAR": "value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 额外目录
|
||||
|
||||
从额外目录加载 hooks:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"internal": {
|
||||
"enabled": true,
|
||||
"load": {
|
||||
"extraDirs": ["/path/to/more/hooks"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 遗留配置格式(仍然支持)
|
||||
|
||||
旧配置格式仍然有效以保持向后兼容:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"internal": {
|
||||
"enabled": true,
|
||||
"handlers": [
|
||||
{
|
||||
"event": "command:new",
|
||||
"module": "./hooks/handlers/my-handler.ts",
|
||||
"export": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**迁移**:对新 hooks 使用基于发现的新系统。遗留处理程序在基于目录的 hooks 之后加载。
|
||||
|
||||
## CLI 命令
|
||||
|
||||
### 列出 Hooks
|
||||
|
||||
```bash
|
||||
# List all hooks
|
||||
openclaw hooks list
|
||||
|
||||
# Show only eligible hooks
|
||||
openclaw hooks list --eligible
|
||||
|
||||
# Verbose output (show missing requirements)
|
||||
openclaw hooks list --verbose
|
||||
|
||||
# JSON output
|
||||
openclaw hooks list --json
|
||||
```
|
||||
|
||||
### Hook 信息
|
||||
|
||||
```bash
|
||||
# Show detailed info about a hook
|
||||
openclaw hooks info session-memory
|
||||
|
||||
# JSON output
|
||||
openclaw hooks info session-memory --json
|
||||
```
|
||||
|
||||
### 检查资格
|
||||
|
||||
```bash
|
||||
# Show eligibility summary
|
||||
openclaw hooks check
|
||||
|
||||
# JSON output
|
||||
openclaw hooks check --json
|
||||
```
|
||||
|
||||
### 启用/禁用
|
||||
|
||||
```bash
|
||||
# Enable a hook
|
||||
openclaw hooks enable session-memory
|
||||
|
||||
# Disable a hook
|
||||
openclaw hooks disable command-logger
|
||||
```
|
||||
|
||||
## 捆绑的 Hooks
|
||||
|
||||
### session-memory
|
||||
|
||||
当你发出 `/new` 时将会话上下文保存到记忆。
|
||||
|
||||
**事件**:`command:new`
|
||||
|
||||
**要求**:必须配置 `workspace.dir`
|
||||
|
||||
**输出**:`<workspace>/memory/YYYY-MM-DD-slug.md`(默认为 `~/.openclaw/workspace`)
|
||||
|
||||
**功能**:
|
||||
|
||||
1. 使用预重置会话条目定位正确的记录
|
||||
2. 提取最后 15 行对话
|
||||
3. 使用 LLM 生成描述性文件名 slug
|
||||
4. 将会话元数据保存到带日期的记忆文件
|
||||
|
||||
**示例输出**:
|
||||
|
||||
```markdown
|
||||
# Session: 2026-01-16 14:30:00 UTC
|
||||
|
||||
- **Session Key**: agent:main:main
|
||||
- **Session ID**: abc123def456
|
||||
- **Source**: telegram
|
||||
```
|
||||
|
||||
**文件名示例**:
|
||||
|
||||
- `2026-01-16-vendor-pitch.md`
|
||||
- `2026-01-16-api-design.md`
|
||||
- `2026-01-16-1430.md`(如果 slug 生成失败则回退到时间戳)
|
||||
|
||||
**启用**:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable session-memory
|
||||
```
|
||||
|
||||
### command-logger
|
||||
|
||||
将所有命令事件记录到集中审计文件。
|
||||
|
||||
**事件**:`command`
|
||||
|
||||
**要求**:无
|
||||
|
||||
**输出**:`~/.openclaw/logs/commands.log`
|
||||
|
||||
**功能**:
|
||||
|
||||
1. 捕获事件详情(命令操作、时间戳、会话键、发送者 ID、来源)
|
||||
2. 以 JSONL 格式追加到日志文件
|
||||
3. 在后台静默运行
|
||||
|
||||
**示例日志条目**:
|
||||
|
||||
```jsonl
|
||||
{"timestamp":"2026-01-16T14:30:00.000Z","action":"new","sessionKey":"agent:main:main","senderId":"+1234567890","source":"telegram"}
|
||||
{"timestamp":"2026-01-16T15:45:22.000Z","action":"stop","sessionKey":"agent:main:main","senderId":"user@example.com","source":"whatsapp"}
|
||||
```
|
||||
|
||||
**查看日志**:
|
||||
|
||||
```bash
|
||||
# View recent commands
|
||||
tail -n 20 ~/.openclaw/logs/commands.log
|
||||
|
||||
# Pretty-print with jq
|
||||
cat ~/.openclaw/logs/commands.log | jq .
|
||||
|
||||
# Filter by action
|
||||
grep '"action":"new"' ~/.openclaw/logs/commands.log | jq .
|
||||
```
|
||||
|
||||
**启用**:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable command-logger
|
||||
```
|
||||
|
||||
### boot-md
|
||||
|
||||
当 Gateway 网关启动时运行 `BOOT.md`(在渠道启动之后)。
|
||||
必须启用内部 hooks 才能运行。
|
||||
|
||||
**事件**:`gateway:startup`
|
||||
|
||||
**要求**:必须配置 `workspace.dir`
|
||||
|
||||
**功能**:
|
||||
|
||||
1. 从你的工作区读取 `BOOT.md`
|
||||
2. 通过智能体运行器运行指令
|
||||
3. 通过 message 工具发送任何请求的出站消息
|
||||
|
||||
**启用**:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable boot-md
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 保持处理程序快速
|
||||
|
||||
Hooks 在命令处理期间运行。保持它们轻量:
|
||||
|
||||
```typescript
|
||||
// ✓ Good - async work, returns immediately
|
||||
const handler: HookHandler = async (event) => {
|
||||
void processInBackground(event); // Fire and forget
|
||||
};
|
||||
|
||||
// ✗ Bad - blocks command processing
|
||||
const handler: HookHandler = async (event) => {
|
||||
await slowDatabaseQuery(event);
|
||||
await evenSlowerAPICall(event);
|
||||
};
|
||||
```
|
||||
|
||||
### 优雅处理错误
|
||||
|
||||
始终包装有风险的操作:
|
||||
|
||||
```typescript
|
||||
const handler: HookHandler = async (event) => {
|
||||
try {
|
||||
await riskyOperation(event);
|
||||
} catch (err) {
|
||||
console.error("[my-handler] Failed:", err instanceof Error ? err.message : String(err));
|
||||
// Don't throw - let other handlers run
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 尽早过滤事件
|
||||
|
||||
如果事件不相关则尽早返回:
|
||||
|
||||
```typescript
|
||||
const handler: HookHandler = async (event) => {
|
||||
// Only handle 'new' commands
|
||||
if (event.type !== "command" || event.action !== "new") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Your logic here
|
||||
};
|
||||
```
|
||||
|
||||
### 使用特定事件键
|
||||
|
||||
尽可能在元数据中指定确切事件:
|
||||
|
||||
```yaml
|
||||
metadata: { "openclaw": { "events": ["command:new"] } } # Specific
|
||||
```
|
||||
|
||||
而不是:
|
||||
|
||||
```yaml
|
||||
metadata: { "openclaw": { "events": ["command"] } } # General - more overhead
|
||||
```
|
||||
|
||||
## 调试
|
||||
|
||||
### 启用 Hook 日志
|
||||
|
||||
Gateway 网关在启动时记录 hook 加载:
|
||||
|
||||
```
|
||||
Registered hook: session-memory -> command:new
|
||||
Registered hook: command-logger -> command
|
||||
Registered hook: boot-md -> gateway:startup
|
||||
```
|
||||
|
||||
### 检查发现
|
||||
|
||||
列出所有发现的 hooks:
|
||||
|
||||
```bash
|
||||
openclaw hooks list --verbose
|
||||
```
|
||||
|
||||
### 检查注册
|
||||
|
||||
在你的处理程序中,记录它被调用的时间:
|
||||
|
||||
```typescript
|
||||
const handler: HookHandler = async (event) => {
|
||||
console.log("[my-handler] Triggered:", event.type, event.action);
|
||||
// Your logic
|
||||
};
|
||||
```
|
||||
|
||||
### 验证资格
|
||||
|
||||
检查为什么 hook 不符合条件:
|
||||
|
||||
```bash
|
||||
openclaw hooks info my-hook
|
||||
```
|
||||
|
||||
在输出中查找缺失的要求。
|
||||
|
||||
## 测试
|
||||
|
||||
### Gateway 网关日志
|
||||
|
||||
监控 Gateway 网关日志以查看 hook 执行:
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
./scripts/clawlog.sh -f
|
||||
|
||||
# Other platforms
|
||||
tail -f ~/.openclaw/gateway.log
|
||||
```
|
||||
|
||||
### 直接测试 Hooks
|
||||
|
||||
隔离测试你的处理程序:
|
||||
|
||||
```typescript
|
||||
import { test } from "vitest";
|
||||
import { createHookEvent } from "./src/hooks/hooks.js";
|
||||
import myHandler from "./hooks/my-hook/handler.js";
|
||||
|
||||
test("my handler works", async () => {
|
||||
const event = createHookEvent("command", "new", "test-session", {
|
||||
foo: "bar",
|
||||
});
|
||||
|
||||
await myHandler(event);
|
||||
|
||||
// Assert side effects
|
||||
});
|
||||
```
|
||||
|
||||
## 架构
|
||||
|
||||
### 核心组件
|
||||
|
||||
- **`src/hooks/types.ts`**:类型定义
|
||||
- **`src/hooks/workspace.ts`**:目录扫描和加载
|
||||
- **`src/hooks/frontmatter.ts`**:HOOK.md 元数据解析
|
||||
- **`src/hooks/config.ts`**:资格检查
|
||||
- **`src/hooks/hooks-status.ts`**:状态报告
|
||||
- **`src/hooks/loader.ts`**:动态模块加载器
|
||||
- **`src/cli/hooks-cli.ts`**:CLI 命令
|
||||
- **`src/gateway/server-startup.ts`**:在 Gateway 网关启动时加载 hooks
|
||||
- **`src/auto-reply/reply/commands-core.ts`**:触发命令事件
|
||||
|
||||
### 发现流程
|
||||
|
||||
```
|
||||
Gateway 网关启动
|
||||
↓
|
||||
扫描目录(工作区 → 托管 → 捆绑)
|
||||
↓
|
||||
解析 HOOK.md 文件
|
||||
↓
|
||||
检查资格(bins、env、config、os)
|
||||
↓
|
||||
从符合条件的 hooks 加载处理程序
|
||||
↓
|
||||
为事件注册处理程序
|
||||
```
|
||||
|
||||
### 事件流程
|
||||
|
||||
```
|
||||
用户发送 /new
|
||||
↓
|
||||
命令验证
|
||||
↓
|
||||
创建 hook 事件
|
||||
↓
|
||||
触发 hook(所有注册的处理程序)
|
||||
↓
|
||||
命令处理继续
|
||||
↓
|
||||
会话重置
|
||||
```
|
||||
|
||||
## 故障排除
|
||||
|
||||
### Hook 未被发现
|
||||
|
||||
1. 检查目录结构:
|
||||
|
||||
```bash
|
||||
ls -la ~/.openclaw/hooks/my-hook/
|
||||
# Should show: HOOK.md, handler.ts
|
||||
```
|
||||
|
||||
2. 验证 HOOK.md 格式:
|
||||
|
||||
```bash
|
||||
cat ~/.openclaw/hooks/my-hook/HOOK.md
|
||||
# Should have YAML frontmatter with name and metadata
|
||||
```
|
||||
|
||||
3. 列出所有发现的 hooks:
|
||||
```bash
|
||||
openclaw hooks list
|
||||
```
|
||||
|
||||
### Hook 不符合条件
|
||||
|
||||
检查要求:
|
||||
|
||||
```bash
|
||||
openclaw hooks info my-hook
|
||||
```
|
||||
|
||||
查找缺失的:
|
||||
|
||||
- 二进制文件(检查 PATH)
|
||||
- 环境变量
|
||||
- 配置值
|
||||
- 操作系统兼容性
|
||||
|
||||
### Hook 未执行
|
||||
|
||||
1. 验证 hook 已启用:
|
||||
|
||||
```bash
|
||||
openclaw hooks list
|
||||
# Should show ✓ next to enabled hooks
|
||||
```
|
||||
|
||||
2. 重启你的 Gateway 网关进程以重新加载 hooks。
|
||||
|
||||
3. 检查 Gateway 网关日志中的错误:
|
||||
```bash
|
||||
./scripts/clawlog.sh | grep hook
|
||||
```
|
||||
|
||||
### 处理程序错误
|
||||
|
||||
检查 TypeScript/import 错误:
|
||||
|
||||
```bash
|
||||
# Test import directly
|
||||
node -e "import('./path/to/handler.ts').then(console.log)"
|
||||
```
|
||||
|
||||
## 迁移指南
|
||||
|
||||
### 从遗留配置到发现
|
||||
|
||||
**之前**:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"internal": {
|
||||
"enabled": true,
|
||||
"handlers": [
|
||||
{
|
||||
"event": "command:new",
|
||||
"module": "./hooks/handlers/my-handler.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**之后**:
|
||||
|
||||
1. 创建 hook 目录:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/hooks/my-hook
|
||||
mv ./hooks/handlers/my-handler.ts ~/.openclaw/hooks/my-hook/handler.ts
|
||||
```
|
||||
|
||||
2. 创建 HOOK.md:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: my-hook
|
||||
description: "My custom hook"
|
||||
metadata: { "openclaw": { "emoji": "🎯", "events": ["command:new"] } }
|
||||
---
|
||||
|
||||
# My Hook
|
||||
|
||||
Does something useful.
|
||||
```
|
||||
|
||||
3. 更新配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"internal": {
|
||||
"enabled": true,
|
||||
"entries": {
|
||||
"my-hook": { "enabled": true }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4. 验证并重启你的 Gateway 网关进程:
|
||||
```bash
|
||||
openclaw hooks list
|
||||
# Should show: 🎯 my-hook ✓
|
||||
```
|
||||
|
||||
**迁移的好处**:
|
||||
|
||||
- 自动发现
|
||||
- CLI 管理
|
||||
- 资格检查
|
||||
- 更好的文档
|
||||
- 一致的结构
|
||||
|
||||
## 另请参阅
|
||||
|
||||
- [CLI 参考:hooks](/cli/hooks)
|
||||
- [捆绑 Hooks README](https://github.com/openclaw/openclaw/tree/main/src/hooks/bundled)
|
||||
- [Webhook Hooks](/automation/webhook)
|
||||
- [配置](/gateway/configuration#hooks)
|
||||
76
content/automation/poll.md
Normal file
76
content/automation/poll.md
Normal file
@@ -0,0 +1,76 @@
|
||||
---
|
||||
read_when:
|
||||
- 添加或修改投票支持
|
||||
- 调试从 CLI 或 Gateway 网关发送的投票
|
||||
summary: 通过 Gateway 网关 + CLI 发送投票
|
||||
title: 投票
|
||||
x-i18n:
|
||||
generated_at: "2026-02-03T07:43:12Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 760339865d27ec40def7996cac1d294d58ab580748ad6b32cc34d285d0314eaf
|
||||
source_path: automation/poll.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 投票
|
||||
|
||||
## 支持的渠道
|
||||
|
||||
- WhatsApp(Web 渠道)
|
||||
- Discord
|
||||
- MS Teams(Adaptive Cards)
|
||||
|
||||
## CLI
|
||||
|
||||
```bash
|
||||
# WhatsApp
|
||||
openclaw message poll --target +15555550123 \
|
||||
--poll-question "Lunch today?" --poll-option "Yes" --poll-option "No" --poll-option "Maybe"
|
||||
openclaw message poll --target 123456789@g.us \
|
||||
--poll-question "Meeting time?" --poll-option "10am" --poll-option "2pm" --poll-option "4pm" --poll-multi
|
||||
|
||||
# Discord
|
||||
openclaw message poll --channel discord --target channel:123456789 \
|
||||
--poll-question "Snack?" --poll-option "Pizza" --poll-option "Sushi"
|
||||
openclaw message poll --channel discord --target channel:123456789 \
|
||||
--poll-question "Plan?" --poll-option "A" --poll-option "B" --poll-duration-hours 48
|
||||
|
||||
# MS Teams
|
||||
openclaw message poll --channel msteams --target conversation:19:abc@thread.tacv2 \
|
||||
--poll-question "Lunch?" --poll-option "Pizza" --poll-option "Sushi"
|
||||
```
|
||||
|
||||
选项:
|
||||
|
||||
- `--channel`:`whatsapp`(默认)、`discord` 或 `msteams`
|
||||
- `--poll-multi`:允许选择多个选项
|
||||
- `--poll-duration-hours`:仅限 Discord(省略时默认为 24)
|
||||
|
||||
## Gateway 网关 RPC
|
||||
|
||||
方法:`poll`
|
||||
|
||||
参数:
|
||||
|
||||
- `to`(字符串,必需)
|
||||
- `question`(字符串,必需)
|
||||
- `options`(字符串数组,必需)
|
||||
- `maxSelections`(数字,可选)
|
||||
- `durationHours`(数字,可选)
|
||||
- `channel`(字符串,可选,默认:`whatsapp`)
|
||||
- `idempotencyKey`(字符串,必需)
|
||||
|
||||
## 渠道差异
|
||||
|
||||
- WhatsApp:2-12 个选项,`maxSelections` 必须在选项数量范围内,忽略 `durationHours`。
|
||||
- Discord:2-10 个选项,`durationHours` 限制在 1-768 小时之间(默认 24)。`maxSelections > 1` 启用多选;Discord 不支持严格的选择数量限制。
|
||||
- MS Teams:Adaptive Card 投票(由 OpenClaw 管理)。无原生投票 API;`durationHours` 被忽略。
|
||||
|
||||
## 智能体工具(Message)
|
||||
|
||||
使用 `message` 工具的 `poll` 操作(`to`、`pollQuestion`、`pollOption`,可选 `pollMulti`、`pollDurationHours`、`channel`)。
|
||||
|
||||
注意:Discord 没有"恰好选择 N 个"模式;`pollMulti` 映射为多选。
|
||||
Teams 投票以 Adaptive Cards 形式渲染,需要 Gateway 网关保持在线
|
||||
以将投票记录到 `~/.openclaw/msteams-polls.json`。
|
||||
8
content/automation/troubleshooting.md
Normal file
8
content/automation/troubleshooting.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
summary: 自动化故障排查:排查 cron 和 heartbeat 调度与投递问题
|
||||
title: 自动化故障排查
|
||||
---
|
||||
|
||||
# 自动化故障排查
|
||||
|
||||
该页面是英文文档的中文占位版本,完整内容请先参考英文版:[Automation Troubleshooting](/automation/troubleshooting)。
|
||||
163
content/automation/webhook.md
Normal file
163
content/automation/webhook.md
Normal file
@@ -0,0 +1,163 @@
|
||||
---
|
||||
read_when:
|
||||
- 添加或更改 webhook 端点
|
||||
- 将外部系统接入 OpenClaw
|
||||
summary: 用于唤醒和隔离智能体运行的 Webhook 入口
|
||||
title: Webhooks
|
||||
x-i18n:
|
||||
generated_at: "2026-02-03T07:43:23Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: f26b88864567be82366b1f66a4772ef2813c7846110c62fce6caf7313568265e
|
||||
source_path: automation/webhook.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# Webhooks
|
||||
|
||||
Gateway 网关可以暴露一个小型 HTTP webhook 端点用于外部触发。
|
||||
|
||||
## 启用
|
||||
|
||||
```json5
|
||||
{
|
||||
hooks: {
|
||||
enabled: true,
|
||||
token: "shared-secret",
|
||||
path: "/hooks",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
注意事项:
|
||||
|
||||
- 当 `hooks.enabled=true` 时,`hooks.token` 为必填项。
|
||||
- `hooks.path` 默认为 `/hooks`。
|
||||
|
||||
## 认证
|
||||
|
||||
每个请求必须包含 hook 令牌。推荐使用请求头:
|
||||
|
||||
- `Authorization: Bearer <token>`(推荐)
|
||||
- `x-openclaw-token: <token>`
|
||||
- `?token=<token>`(已弃用;会记录警告日志,将在未来的主要版本中移除)
|
||||
|
||||
## 端点
|
||||
|
||||
### `POST /hooks/wake`
|
||||
|
||||
请求体:
|
||||
|
||||
```json
|
||||
{ "text": "System line", "mode": "now" }
|
||||
```
|
||||
|
||||
- `text` **必填**(字符串):事件描述(例如"收到新邮件")。
|
||||
- `mode` 可选(`now` | `next-heartbeat`):是否立即触发心跳(默认 `now`)或等待下一次定期检查。
|
||||
|
||||
效果:
|
||||
|
||||
- 为**主**会话加入一个系统事件队列
|
||||
- 如果 `mode=now`,则立即触发心跳
|
||||
|
||||
### `POST /hooks/agent`
|
||||
|
||||
请求体:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Run this",
|
||||
"name": "Email",
|
||||
"sessionKey": "hook:email:msg-123",
|
||||
"wakeMode": "now",
|
||||
"deliver": true,
|
||||
"channel": "last",
|
||||
"to": "+15551234567",
|
||||
"model": "openai/gpt-5.2-mini",
|
||||
"thinking": "low",
|
||||
"timeoutSeconds": 120
|
||||
}
|
||||
```
|
||||
|
||||
- `message` **必填**(字符串):智能体要处理的提示或消息。
|
||||
- `name` 可选(字符串):hook 的可读名称(例如"GitHub"),用作会话摘要的前缀。
|
||||
- `sessionKey` 可选(字符串):用于标识智能体会话的键。默认为随机的 `hook:<uuid>`。使用一致的键可以在 hook 上下文中进行多轮对话。
|
||||
- `wakeMode` 可选(`now` | `next-heartbeat`):是否立即触发心跳(默认 `now`)或等待下一次定期检查。
|
||||
- `deliver` 可选(布尔值):如果为 `true`,智能体的响应将发送到消息渠道。默认为 `true`。仅为心跳确认的响应会自动跳过。
|
||||
- `channel` 可选(字符串):用于投递的消息渠道。可选值:`last`、`whatsapp`、`telegram`、`discord`、`slack`、`mattermost`(插件)、`signal`、`imessage`、`msteams`。默认为 `last`。
|
||||
- `to` 可选(字符串):渠道的接收者标识符(例如 WhatsApp/Signal 的电话号码、Telegram 的聊天 ID、Discord/Slack/Mattermost(插件)的频道 ID、MS Teams 的会话 ID)。默认为主会话中的最后一个接收者。
|
||||
- `model` 可选(字符串):模型覆盖(例如 `anthropic/claude-3-5-sonnet` 或别名)。如果有限制,必须在允许的模型列表中。
|
||||
- `thinking` 可选(字符串):思考级别覆盖(例如 `low`、`medium`、`high`)。
|
||||
- `timeoutSeconds` 可选(数字):智能体运行的最大持续时间(秒)。
|
||||
|
||||
效果:
|
||||
|
||||
- 运行一个**隔离的**智能体回合(独立的会话键)
|
||||
- 始终在**主**会话中发布摘要
|
||||
- 如果 `wakeMode=now`,则立即触发心跳
|
||||
|
||||
### `POST /hooks/<name>`(映射)
|
||||
|
||||
自定义 hook 名称通过 `hooks.mappings` 解析(见配置)。映射可以将任意请求体转换为 `wake` 或 `agent` 操作,支持可选的模板或代码转换。
|
||||
|
||||
映射选项(摘要):
|
||||
|
||||
- `hooks.presets: ["gmail"]` 启用内置的 Gmail 映射。
|
||||
- `hooks.mappings` 允许你在配置中定义 `match`、`action` 和模板。
|
||||
- `hooks.transformsDir` + `transform.module` 加载 JS/TS 模块用于自定义逻辑。
|
||||
- 使用 `match.source` 保持通用的接收端点(基于请求体的路由)。
|
||||
- TS 转换需要 TS 加载器(例如 `bun` 或 `tsx`)或运行时预编译的 `.js`。
|
||||
- 在映射上设置 `deliver: true` + `channel`/`to` 可将回复路由到聊天界面(`channel` 默认为 `last`,回退到 WhatsApp)。
|
||||
- `allowUnsafeExternalContent: true` 禁用该 hook 的外部内容安全包装(危险;仅用于受信任的内部来源)。
|
||||
- `openclaw webhooks gmail setup` 为 `openclaw webhooks gmail run` 写入 `hooks.gmail` 配置。完整的 Gmail 监听流程请参阅 [Gmail Pub/Sub](/automation/gmail-pubsub)。
|
||||
|
||||
## 响应
|
||||
|
||||
- `200` 用于 `/hooks/wake`
|
||||
- `202` 用于 `/hooks/agent`(异步运行已启动)
|
||||
- `401` 认证失败
|
||||
- `400` 请求体无效
|
||||
- `413` 请求体过大
|
||||
|
||||
## 示例
|
||||
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:18789/hooks/wake \
|
||||
-H 'Authorization: Bearer SECRET' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"text":"New email received","mode":"now"}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:18789/hooks/agent \
|
||||
-H 'x-openclaw-token: SECRET' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"message":"Summarize inbox","name":"Email","wakeMode":"next-heartbeat"}'
|
||||
```
|
||||
|
||||
### 使用不同的模型
|
||||
|
||||
在智能体请求体(或映射)中添加 `model` 以覆盖该次运行的模型:
|
||||
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:18789/hooks/agent \
|
||||
-H 'x-openclaw-token: SECRET' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"message":"Summarize inbox","name":"Email","model":"openai/gpt-5.2-mini"}'
|
||||
```
|
||||
|
||||
如果你启用了 `agents.defaults.models` 限制,请确保覆盖的模型包含在其中。
|
||||
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:18789/hooks/gmail \
|
||||
-H 'Authorization: Bearer SECRET' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"source":"gmail","messages":[{"from":"Ada","subject":"Hello","snippet":"Hi"}]}'
|
||||
```
|
||||
|
||||
## 安全
|
||||
|
||||
- 将 hook 端点保持在 loopback、tailnet 或受信任的反向代理之后。
|
||||
- 使用专用的 hook 令牌;不要复用 Gateway 网关认证令牌。
|
||||
- 避免在 webhook 日志中包含敏感的原始请求体。
|
||||
- Hook 请求体默认被视为不受信任并使用安全边界包装。如果你必须为特定 hook 禁用此功能,请在该 hook 的映射中设置 `allowUnsafeExternalContent: true`(危险)。
|
||||
Reference in New Issue
Block a user