diff --git a/skills/autonomous-ai-agents/hermes-agent/references/webhooks.md b/skills/autonomous-ai-agents/hermes-agent/references/webhooks.md index 0af935ea23c..a815cac50d4 100644 --- a/skills/autonomous-ai-agents/hermes-agent/references/webhooks.md +++ b/skills/autonomous-ai-agents/hermes-agent/references/webhooks.md @@ -67,6 +67,22 @@ hermes webhook subscribe \ Returns the webhook URL and HMAC secret. The user configures their service to POST to that URL. +### Filter or transform payloads before the agent runs + +Two mechanisms narrow broad event streams (e.g. Todoist/GitHub fire on every update) so only relevant payloads wake the agent: + +- **Declarative `filters`** (config.yaml routes only): list of conditions on payload fields, event type, or headers — operators `equals`, `not_equals`, `contains`, `exists`, `missing`, `in`, `in_file`, `regex`, with `all`/`any`/`not` grouping. Non-matching events are ignored with HTTP 200. +- **Route scripts** (`--script` on subscribe, or `script:` on a config route): a script under `~/.hermes/scripts/` receives the payload as JSON on stdin. JSON stdout replaces the payload before prompt templating; empty stdout, `[SILENT]`, or a nonzero exit ignores the webhook. `.sh`/`.bash` run with bash, everything else with Python. Scripts cannot live outside `~/.hermes/scripts/` (path traversal is blocked). + +```bash +hermes webhook subscribe todoist-hermes \ + --prompt "Task changed: {payload.content}" \ + --script "todoist-hermes-label.py" \ + --deliver telegram --deliver-chat-id "12345" +``` + +Full filter syntax: https://hermes-agent.nousresearch.com/docs/user-guide/messaging/webhooks#payload-filters + ### List subscriptions ```bash hermes webhook list diff --git a/website/docs/reference/cli-commands.md b/website/docs/reference/cli-commands.md index b8ace5b1912..6fa916786f3 100644 --- a/website/docs/reference/cli-commands.md +++ b/website/docs/reference/cli-commands.md @@ -671,6 +671,7 @@ hermes webhook subscribe [options] | `--deliver-chat-id` | Target chat/channel ID for cross-platform delivery. | | `--secret` | Custom HMAC secret. Auto-generated if omitted. | | `--deliver-only` | Skip the agent — deliver the rendered `--prompt` as the literal message. Zero LLM cost, sub-second delivery. Requires `--deliver` to be a real target (not `log`). | +| `--script` | Filter/transform script under `~/.hermes/scripts/`. The webhook payload is passed as JSON on stdin; JSON stdout replaces the payload, and empty stdout, `[SILENT]`, or a nonzero exit code ignores the webhook. See [Script Filters and Transforms](../user-guide/messaging/webhooks.md#script-filters-and-transforms). | Subscriptions persist to `~/.hermes/webhook_subscriptions.json` and are hot-reloaded by the webhook adapter without a gateway restart. diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/cli-commands.md b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/cli-commands.md index 5c6a85144ff..a1191cfbd5f 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/cli-commands.md +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/cli-commands.md @@ -477,6 +477,7 @@ hermes webhook subscribe [options] | `--deliver-chat-id` | 跨平台投递的目标聊天/频道 ID。 | | `--secret` | 自定义 HMAC 密钥。省略时自动生成。 | | `--deliver-only` | 跳过 agent——将渲染后的 `--prompt` 作为字面消息投递。零 LLM 成本,亚秒级投递。要求 `--deliver` 为真实目标(非 `log`)。 | +| `--script` | 位于 `~/.hermes/scripts/` 下的过滤/转换脚本。webhook payload 以 JSON 形式通过 stdin 传入;JSON stdout 会替换 payload,空 stdout、`[SILENT]` 或非零退出码会忽略该 webhook。参见[脚本过滤与转换](../user-guide/messaging/webhooks.md#script-filters-and-transforms)。 | 订阅持久化到 `~/.hermes/webhook_subscriptions.json`,webhook 适配器无需重启 gateway 即可热重载。 diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/messaging/webhooks.md b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/messaging/webhooks.md index 491bd3f8995..82597095fa1 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/messaging/webhooks.md +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/messaging/webhooks.md @@ -81,6 +81,8 @@ curl http://localhost:8644/health | `events` | 否 | 要接受的事件类型列表(例如 `["pull_request"]`)。若为空,则接受所有事件。事件类型从 `X-GitHub-Event`、`X-GitLab-Event` 或 payload 中的 `event_type` 读取。 | | `secret` | **是** | 用于签名验证的 HMAC secret。若路由未设置,则回退到全局 `secret`。仅用于测试时可设为 `"INSECURE_NO_AUTH"`(跳过验证)。 | | `prompt` | 否 | 使用点号表示法访问 payload 字段的模板字符串(例如 `{pull_request.title}`)。若省略,则将完整 JSON payload 转储到 prompt 中。 | +| `filters` | 否 | 声明式 payload 过滤器,在认证/请求体/事件过滤之后、agent 或直接投递之前求值。不匹配时返回 `{"status":"ignored","reason":"filter"}`(HTTP 200)。 | +| `script` | 否 | 位于 `~/.hermes/scripts/` 下的过滤/转换脚本。webhook payload 以 JSON 形式通过 stdin 传入。stdout 为 JSON 对象时会在模板渲染前替换 payload;文本 stdout 以 `script_output` 形式暴露;空 stdout、`[SILENT]` 或非零退出码会忽略该 webhook。 | | `skills` | 否 | agent 运行时加载的 skill 名称列表。 | | `deliver` | 否 | 响应发送目标:`github_comment`、`telegram`、`discord`、`slack`、`signal`、`sms`、`whatsapp`、`matrix`、`mattermost`、`homeassistant`、`email`、`dingtalk`、`feishu`、`wecom`、`weixin`、`bluebubbles`、`qqbot`,或 `log`(默认)。 | | `deliver_extra` | 否 | 额外的投递配置——键取决于 `deliver` 类型(例如 `repo`、`pr_number`、`chat_id`)。值支持与 `prompt` 相同的 `{dot.notation}` 模板语法。 | @@ -116,9 +118,75 @@ platforms: events: ["push"] secret: "deploy-secret" prompt: "New push to {repository.full_name} branch {ref}: {head_commit.message}" + filters: + - field: "ref" + equals: "refs/heads/main" deliver: "telegram" ``` +### Payload 过滤器 {#payload-filters} + +当服务商发送宽泛的事件流、但只有部分 payload 应唤醒 agent 或触发 `deliver_only` 投递时,使用 `filters`。过滤器在签名验证、请求体解析和 `events` 之后运行,但在 prompt 渲染、幂等去重、agent 调度或直接投递之前运行。 + +```yaml +platforms: + webhook: + extra: + routes: + todoist: + events: ["item:updated"] + secret: "todoist-secret" + filters: + - field: "payload.labels" + contains: "hermes" + - any: + - field: "payload.priority" + equals: 4 + - field: "payload.project_id" + in_file: "~/.hermes/data/todoist/watchlist.json" + prompt: "Todoist task changed: {payload.content}" +``` + +支持的操作符: + +- `exists: true|false` +- `missing: true` +- `equals` / `not_equals` +- `contains` — 适用于字符串、列表和 dict 键 +- `in` — 内联列表 +- `in_file` — JSON 数组、JSON 对象(使用其键)或按行分隔的文本文件 +- `regex` +- `all`、`any` 和 `not` 分组 + +字段路径使用点号表示法。当存在顶层 `payload` 对象时,`payload.foo` 从中读取;对扁平 payload 则从 webhook 请求体根部读取。`event` / `event_type` 匹配解析出的事件类型,`headers.` 读取请求头。 + +### 脚本过滤与转换 {#script-filters-and-transforms} + +当声明式过滤器不够用时,使用 `script`。脚本必须位于当前 profile 的 `~/.hermes/scripts/` 目录下;相对路径在该目录内解析,且禁止路径穿越到目录之外。`.sh` 和 `.bash` 脚本用 bash 运行,其他扩展名用当前 Python 解释器运行。 + +路由 payload 以 JSON 形式发送到 stdin: + +```python +# ~/.hermes/scripts/todoist-hermes-label.py +import json +import sys + +payload = json.load(sys.stdin) +labels = payload.get("payload", {}).get("labels", []) +if "hermes" not in labels: + print("[SILENT]") + raise SystemExit(0) + +payload["body"] = payload["payload"]["content"] +print(json.dumps(payload)) +``` + +脚本结果: + +- stdout 为 JSON 对象时,替换 `prompt` 和 `deliver_extra` 使用的 payload。 +- 非 JSON 文本 stdout 会以 `script_output` 字段加入 payload。 +- 空 stdout、精确的 `[SILENT]`、`{"__hermes_ignore__": true}`、超时、脚本缺失或非零退出码,均返回 HTTP 200 及 `{"status":"ignored","reason":"script"}`。 + ### Prompt 模板 Prompt 使用点号表示法访问 webhook payload 中的嵌套字段: