Webhooks
通过 Webhook 从外部服务(如 GitHub、GitLab、JIRA、Stripe 等)接收事件,并自动触发 Hermes Agent 的运行。Webhook 适配器运行一个 HTTP 服务器,接收 POST 请求,验证 HMAC 签名,将请求体转换为 Agent 提示(prompt),并将响应路由回源服务或配置的其他平台。
Agent 处理事件后,可执行以下操作:在 PR 上发表评论、向 Telegram/Discord 发送消息,或记录结果。
快速开始
- 通过
HERMES_INLINE_19_TOKEN或环境变量启用 - 在
HERMES_INLINE_20_TOKEN中定义路由 或 使用HERMES_INLINE_21_TOKEN动态创建路由 - 将你的服务指向
HERMES_INLINE_22_TOKEN
设置
有两种方式启用 Webhook 适配器。
通过设置向导
HERMES_FENCE_0_TOKEN
按照提示启用 Webhooks,设置端口,并设置全局 HMAC 密钥。
通过环境变量
将以下内容添加至 HERMES_INLINE_23_TOKEN:
HERMES_FENCE_1_TOKEN
验证服务器
一旦网关启动成功:
HERMES_FENCE_2_TOKEN
预期响应:
HERMES_FENCE_3_TOKEN
配置路由 HERMES_EXPR_181_TOKEN
路由定义了如何处理不同来源的 Webhook。每个路由是您 HERMES_INLINE_24_TOKEN 中 HERMES_INLINE_25_TOKEN 下的一个命名条目。
路由属性
| 属性 | 是否必需 | 描述 |
|---|---|---|
HERMES_INLINE_26_TOKEN | 否 | 要接受的事件类型列表(例如 HERMES_INLINE_27_TOKEN)。若为空,则接受所有事件。事件类型从 payload 中的 HERMES_INLINE_28_TOKEN、HERMES_INLINE_29_TOKEN 或 HERMES_INLINE_30_TOKEN 读取。 |
HERMES_INLINE_31_TOKEN | 是 | 用于签名验证的 HMAC 密钥。若未在路由中设置,则回退到全局 HERMES_INLINE_32_TOKEN。仅在测试时设为 HERMES_INLINE_33_TOKEN(跳过验证)。 |
HERMES_INLINE_34_TOKEN | 否 | 使用点表示法访问 payload 的模板字符串(例如 HERMES_INLINE_35_TOKEN)。若省略,则将完整 JSON payload 作为提示输入。 |
HERMES_INLINE_36_TOKEN | 否 | 为本次 Agent 运行加载的技能名称列表。 |
HERMES_INLINE_37_TOKEN | 否 | 响应发送目标:HERMES_INLINE_38_TOKEN、HERMES_INLINE_39_TOKEN、HERMES_INLINE_40_TOKEN、HERMES_INLINE_41_TOKEN、HERMES_INLINE_42_TOKEN、HERMES_INLINE_43_TOKEN、HERMES_INLINE_44_TOKEN、HERMES_INLINE_45_TOKEN、HERMES_INLINE_46_TOKEN、HERMES_INLINE_47_TOKEN、HERMES_INLINE_48_TOKEN、HERMES_INLINE_49_TOKEN、HERMES_INLINE_50_TOKEN、HERMES_INLINE_51_TOKEN、HERMES_INLINE_52_TOKEN、HERMES_INLINE_53_TOKEN、HERMES_INLINE_54_TOKEN,或 HERMES_INLINE_55_TOKEN(默认)。 |
HERMES_INLINE_56_TOKEN | 否 | 额外交付配置 —— 键取决于 HERMES_INLINE_57_TOKEN 类型(例如 HERMES_INLINE_58_TOKEN、HERMES_INLINE_59_TOKEN、HERMES_INLINE_60_TOKEN)。值支持与 HERMES_INLINE_61_TOKEN 相同的 HERMES_INLINE_62_TOKEN 模板。 |
完整示例
HERMES_FENCE_4_TOKEN
提示模板
提示使用点表示法访问 Webhook payload 中的嵌套字段:
HERMES_INLINE_63_TOKEN解析为HERMES_INLINE_64_TOKENHERMES_INLINE_65_TOKEN解析为HERMES_INLINE_66_TOKENHERMES_INLINE_67_TOKEN— 特殊标记,将 整个 payload 以缩进格式的 JSON 输出(截断至 4000 字符)。适用于监控告警或通用 Webhook,此时 Agent 需要完整上下文。- 缺失的键将保留为字面量
HERMES_INLINE_68_TOKEN字符串(不报错) - 嵌套的字典和列表会被 JSON 序列化,并在 2000 字符处截断
你可以在普通模板变量中混合使用 HERMES_INLINE_69_TOKEN:
HERMES_FENCE_5_TOKEN
如果某个路由未配置 HERMES_INLINE_70_TOKEN 模板,则会将整个 payload 以缩进 JSON 格式输出(截断至 4000 字符)。
相同的点表示法模板也适用于 HERMES_INLINE_71_TOKEN 的值。
论坛主题投递
当向 Telegram 投递 Webhook 响应时,可通过在 HERMES_INLINE_74_TOKEN 中包含 HERMES_INLINE_72_TOKEN(或 HERMES_INLINE_73_TOKEN)来指定特定论坛主题:
HERMES_FENCE_6_TOKEN
如果 HERMES_INLINE_75_TOKEN 未在 HERMES_INLINE_76_TOKEN 中提供,投递将回退到目标平台配置的主频道。
GitHub PR 审查(分步指南)HERMES_EXPR_182_TOKEN
本教程将设置每次拉取请求(Pull Request)自动触发代码审查。
1. 在 GitHub 中创建 Webhook
- 进入你的仓库 → Settings → Webhooks → Add webhook
- 设置 Payload URL 为
HERMES_URL_16_TOKEN - 设置 Content type 为
HERMES_INLINE_77_TOKEN - 设置 Secret 与你的路由配置匹配(例如
HERMES_INLINE_78_TOKEN) - 在 Which events? 中选择 Let me select individual events,并勾选 Pull requests
- 点击 Add webhook
2. 添加路由配置
将 HERMES_INLINE_79_TOKEN 路由添加至你的 HERMES_INLINE_80_TOKEN,如上例所示。
3. 确保 HERMES_INLINE_81_TOKEN CLI 已认证
HERMES_INLINE_82_TOKEN 交付类型使用 GitHub CLI 发布评论:
HERMES_FENCE_7_TOKEN
4. 测试
在仓库中打开一个拉取请求。Webhook 触发后,Hermes 处理事件,并在 PR 上发布评审评论。
GitLab Webhook 设置 HERMES_EXPR_183_TOKEN
GitLab Webhooks 的工作方式类似,但使用不同的认证机制。GitLab 以明文形式发送密钥作为 HERMES_INLINE_83_TOKEN 头部(精确字符串匹配,非 HMAC)。
1. 在 GitLab 中创建 Webhook
- 进入你的项目 → Settings → Webhooks
- 设置 URL 为
HERMES_URL_17_TOKEN - 输入你的 Secret token
- 选择 Merge request events(及其他你希望监听的事件)
- 点击 Add webhook
2. 添加路由配置
HERMES_FENCE_8_TOKEN
交付选项 HERMES_EXPR_184_TOKEN
HERMES_INLINE_84_TOKEN 字段控制 Agent 处理 Webhook 事件后的响应去向。| 交付类型 (Deliver Type) | 描述 (Description) |
|------------------------|--------------------|
| log | 将响应记录到网关日志输出中。这是默认选项,适用于测试。 |
| github_comment | 通过 gh CLI 将响应作为 PR/Issue 评论发布。需要配置 deliver_extra.repo 和 deliver_extra.pr_number。必须在网关主机(gh auth login)上安装并认证 gh CLI。 |
| telegram | 将响应路由至 Telegram。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| discord | 将响应路由至 Discord。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| slack | 将响应路由至 Slack。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| signal | 将响应路由至 Signal。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| sms | 通过 Twilio 将响应路由至 SMS。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| whatsapp | 将响应路由至 WhatsApp。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| matrix | 将响应路由至 Matrix。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| mattermost | 将响应路由至 Mattermost。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| homeassistant | 将响应路由至 Home Assistant。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| email | 将响应路由至 Email。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| dingtalk | 将响应路由至 DingTalk。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| feishu | 将响应路由至 Feishu/Lark。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| wecom | 将响应路由至 WeCom。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| weixin | 将响应路由至 Weixin(微信)。使用主频道,或在 deliver_extra 中指定 chat_id。 |
| bluebubbles | 将响应路由至 BlueBubbles(iMessage)。使用主频道,或在 deliver_extra 中指定 chat_id。 |
对于跨平台交付,目标平台也必须在网关中启用并连接。如果在 deliver_extra 中未提供 chat_id,则响应将发送至该平台配置的主频道。
动态订阅(CLI)
除了 config.yaml 中的静态路由外,还可以使用 hermes webhook CLI 命令动态创建 Webhook 订阅。当代理自身需要设置事件驱动触发器时尤其有用。
创建订阅
hermes webhook subscribe github-issues \
--events "issues" \
--prompt "New issue #{issue.number}: {issue.title}\nBy: {issue.user.login}\n\n{issue.body}" \
--deliver telegram \
--deliver-chat-id "-100123456789" \
--description "Triage new GitHub issues"
此命令返回 Webhook URL 和一个自动生成的 HMAC 密钥。请配置您的服务向该 URL 发送 POST 请求。
列出订阅
hermes webhook list
删除订阅
hermes webhook remove github-issues
测试订阅
hermes webhook test github-issues
hermes webhook test github-issues --payload '{"issue": {"number": 42, "title": "Test"}}'
动态订阅的工作原理
- 订阅信息存储在
~/.hermes/webhook_subscriptions.json中 - Webhook 适配器在每次接收到请求时热重载该文件(基于 mtime 的机制,开销可忽略)
- 静态路由(来自
config.yaml)始终优先于同名的动态路由 - 动态订阅使用与静态路由相同的格式和功能(事件、提示模板、技能、交付方式)
- 无需重启网关——订阅后立即生效
由代理驱动的订阅
代理可通过终端工具,在 webhook-subscriptions 技能的引导下创建订阅。例如,让代理“为 GitHub Issues 设置 Webhook”,它将自动执行相应的 hermes webhook subscribe 命令。
安全性
Webhook 适配器包含多层安全机制:
HMAC 签名验证
适配器使用各源对应的适当方法验证传入的 Webhook 签名:
- GitHub:
X-Hub-Signature-256头 —— 以sha256=开头的 HMAC-SHA256 十六进制摘要 - GitLab:
X-Gitlab-Token头 —— 直接匹配原始密钥字符串 - 通用情况:
X-Webhook-Signature头 —— 原始 HMAC-SHA256 十六进制摘要
如果已配置密钥但未检测到受支持的签名头,请求将被拒绝。
密钥为必填项
每个路由都必须配置密钥 —— 可直接在路由中设置,或从全局 secret 继承。没有密钥的路由将在网关启动时失败并报错。仅用于开发/测试时,可将密钥设为 "INSECURE_NO_AUTH" 以完全跳过验证。
速率限制
每条路由默认限速为 每分钟 30 次请求(固定窗口)。可全局配置:
platforms:
webhook:
extra:
rate_limit: 60 # requests per minute
超过限制的请求将收到 429 Too Many Requests 响应。
幂等性
交付 ID(来自 X-GitHub-Delivery、X-Request-ID 或时间戳回退)将缓存 1 小时。重复交付(如 Webhook 重试)会静默跳过,并返回 200 响应,防止代理重复运行。
请求体大小限制
超过 1 MB 的负载将在读取前被拒绝。可配置:
platforms:
webhook:
extra:
max_body_bytes: 2097152 # 2 MB
提示注入风险
Webhook 负载包含攻击者可控的数据 —— PR 标题、提交信息、Issue 描述等均可能包含恶意指令。当网关暴露于互联网时,请务必在沙箱环境(Docker、虚拟机)中运行。建议使用 Docker 或 SSH 终端后端以实现隔离。
故障排查
Webhook 未到达
- 确认端口已暴露且可从 Webhook 来源访问
- 检查防火墙规则 —— 端口
8644(或您配置的端口)必须开放 - 确认 URL 路径匹配:
http://your-server:8644/webhooks/<route-name> - 使用
/health端点确认服务器正在运行
签名验证失败
- 确保路由配置中的密钥与 Webhook 来源配置的密钥完全一致
- 对于 GitHub,密钥为 HMAC 类型 —— 请检查
X-Hub-Signature-256 - 对于 GitLab,密钥为明文令牌匹配 —— 请检查
X-Gitlab-Token - 查看网关日志中的
Invalid signature警告信息
事件被忽略
- 检查事件类型是否在路由的
events列表中 - GitHub 事件使用值如
pull_request、push、issues(即X-GitHub-Event头的值) - GitLab 事件使用值如
merge_request、push(即X-GitLab-Event头的值) - 若
events为空或未设置,则接受所有事件
代理无响应
- 以前台模式运行网关以查看日志:
hermes gateway run - 检查提示模板是否正确渲染
- 确认交付目标已正确配置并已连接
重复响应
- 幂等性缓存应可防止此问题 —— 检查 Webhook 来源是否发送了交付 ID 头(
X-GitHub-Delivery或X-Request-ID) - 交付 ID 缓存时间为 1 小时
gh CLI 错误(GitHub 评论交付)
- 在网关主机上运行
gh auth login - 确保已认证的 GitHub 用户对仓库具有写权限
- 检查
gh是否已安装且在 PATH 中
环境变量 {#environment-variables}| 变量 | 描述 | 默认值 |
|----------|-------------|---------|
| WEBHOOK_ENABLED | 启用 webhook 平台适配器 | false |
| WEBHOOK_PORT | 接收 webhook 的 HTTP 服务器端口 | 8644 |
| WEBHOOK_SECRET | 全局 HMAC 密钥(当路由未指定自己的密钥时作为备用) | (无) |