Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

SOP Fan-In:Webhook

网关为由 webhook 触发的 SOP 提供两个经过身份验证的 HTTP 入口:

  • POST /sop/{path} 仅用于 SOP。它会分派匹配的 SOP;当没有任何已加载的 SOP 声明了该确切路径时,返回 404。它绝不会回退到代理或模型调用。
  • POST /webhook 会先检查是否存在完全匹配的 /webhook SOP 触发器。如果没有匹配项,则保留正常的 webhook 聊天行为。

请在配置了 sop.sops_dir 的情况下,通过 zeroclaw daemon 运行这些端点。它们使用守护进程共享的 SOP 引擎。单独运行 zeroclaw gateway start,或未启用 SOP 子系统的守护进程,会从 /sop/* 返回 503

触发器

传入的 HTTP 请求。已上线:网关 /sop/* 和 SOP 优先的 /webhook 路由。

字段类型默认含义
path*字符串请求路径与事件路径完全匹配。

加载并验证 SOP:

定义

按照 Syntax 中所述编写 SOP,并使用 webhook 触发器。上面的触发器字段是支持的键;该页面会逐步介绍整个文件。

验证

zeroclaw sop validate

检查

zeroclaw sop list
zeroclaw sop show <name>

路径匹配是精确的。例如:

[[triggers]]
type = "webhook"
path = "/sop/deploy"

POST /sop/deploy 触发,但不会对 /sop/deploy//sop/deploy/production 触发。

请求和响应

/sop/* 接受空请求体或任何有效的 JSON 值。请求路径将成为事件主题,规范化的 JSON 请求体将成为其负载。无效的 JSON 返回 400

发送所有已配置的控制项。设置了 gateway.require_pairing = true gateway.webhook_secret(如下所示的配置)后,一个完整请求会同时携带这两项:

curl -X POST http://127.0.0.1:42617/sop/deploy \
  -H 'Authorization: Bearer <paired-token>' \
  -H 'X-Webhook-Secret: <gateway.webhook_secret>' \
  -H 'Content-Type: application/json' \
  -H 'X-Idempotency-Key: deploy-2026-07-20-001' \
  -d '{"revision":"abc123"}'

仅配置一个控件时,只发送该控件:

# gateway.webhook_secret 已设置,无需配对
curl -X POST http://127.0.0.1:42617/sop/deploy \
  -H 'X-Webhook-Secret: <gateway.webhook_secret>' \
  -H 'Content-Type: application/json' \
  -d '{"revision":"abc123"}'

# gateway.require_pairing = true, no webhook secret configured
curl -X POST http://127.0.0.1:42617/sop/deploy \
  -H 'Authorization: Bearer <paired-token>' \
  -H 'Content-Type: application/json' \
  -d '{"revision":"abc123"}'

成功匹配时返回 200,每个匹配的 SOP 对应一个结果。skippeddeferredcoalesced 等准入结果会在该数组中报告。被 SOP 不可信输入防护机制拒绝的输入返回 422

身份验证和幂等性

两个入口都使用网关 Webhook 安全控制:

  • 网关需要配对时的配对承载身份验证;
  • gateway.webhook_secret 配置的可选 X-Webhook-Secret;以及
  • webhook 速率限制

启动 SOP 运行会触发真实副作用,因此调度采用失败关闭策略:必须配置至少一个控制项。所有已配置的控制项都必须通过验证:需要配对时,发送有效的 Authorization: Bearer <paired-token>;设置了 gateway.webhook_secret 时,在 X-Webhook-Secret 中发送其确切值;两者均已配置时,发送两者。

凭据策略按每个请求读取一次。授权会捕获一份不可变快照,记录配置了哪些控制项以及请求满足了其中哪些控制项,SOP 分发门控仅根据该快照作出决定。因此,请求处理期间生效的配置更改不会在单个请求内混合两种安全状态:未提供凭据的请求不会因为处理期间添加了密钥而获准通过,携带已停用密钥的请求也不会因为其替代密钥已存在而获准通过。轮换从下一个请求开始生效。

[gateway]
webhook_secret = "replace-with-a-random-secret"

[channels.webhook.<alias>].secret 不是网关凭据。它属于独立的 webhook 通道侦听器,用于验证 X-Webhook-Signature: sha256=<HMAC>。多个通道别名(包括已禁用或过期的别名)绝不会影响网关/SOP 授权。

在未配置任何网关控制措施时(例如 gateway.require_pairing = false 且未设置 gateway.webhook_secret),/sop/* 会在解析 JSON 或访问 SOP 引擎之前返回相同的 401。因此,匿名调用方无法区分 JSON 格式错误、引擎是否可用,或路径是否匹配。对于 /webhook,凭据要求的故障关闭策略仅在 SOP 触发器匹配时适用;未匹配的请求仍保留现有的聊天回退策略。

可选的 X-Idempotency-Key 重放保护按 SOP 路径进行命名空间隔离,而不仅仅是按端点族隔离:发送到两个不同 SOP 路径的同一个键(例如先发送到 /sop/deploy,再发送到 /sop/rollback)会被视为两个不同的请求,并且 /sop/* 键绝不会与 /webhook 键发生冲突。存储的键是端点域、路径命名空间和调用方键的长度前缀编码,因此具有单射性:调用方无法构造出会落入另一路径或另一端点重放槽位的值。HTTP 交付按尝试保证至多一次:该键会在分派前预留,因此像匹配与分派之间发生 SOP 卸载这样的竞态,可能会消耗该键,却不启动一次运行。因此,重复响应表示先前的请求已预留该键,且没有启动新的分派;它并不表示先前的尝试已成功完成。deferred 结果可以被观察到,但网关不会自动重试该结果。

另见