尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

oh-my-claudecode OpenClaw/Clawhip 路由契约解读:基于 signal 的统一事件载荷与下游路由实践

oh-my-claudecode OpenClaw/Clawhip 路由契约解读:基于 signal 的统一事件载荷与下游路由实践 oh-my-claudecode OpenClaw/Clawhip 路由契约解读基于 signal 的统一事件载荷与下游路由实践【免费下载链接】oh-my-claudecodeTeams-first Multi-agent orchestration for Claude Code项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-claudecode本篇技术指南围绕 oh-my-claudecode 项目中 OpenClaw/Clawhip 路由契约 展开系统讲解该项目通过 OpenClaw bridge 向原生 Clawhip 风格消费者输出的归一化事件契约如何在保留原始 hook 事件event的同时新增可供路由与去重过滤的signal对象并让 HTTP 网关与原生命令行网关收到完全一致的逻辑载荷。读完本文你将掌握signal的字段语义、全部高优先级 route key、噪音抑制机制以及基于 src/openclaw 源码的底层实现原理。一、为什么需要统一路由契约oh-my-claudecode简称 OMC为 Claude Code 提供了大量 hook 生命周期事件会话开始/结束、工具调用、提问、关键词命中等。在早期形态下这些事件以各不相同的原始载荷直接推送给下游消费者导致两类问题事件命名与字段不统一会话、测试、PR、提问等逻辑信号与原始 hook 名称混杂下游消费者不得不在裸 hook 名上做脆弱的字符串路由。HTTP 网关与命令行网关体验割裂HTTP 网关接收的是结构化 JSON而基于 shell 命令的原生 Clawhip 网关只能拿到零散的模板变量两边无法共享同一套路由逻辑。docs/OPENCLAW-ROUTING.md定义的正是一个归一化事件契约其三大目标文档 Goals 章节可概括为保留向后兼容原始 hook 事件event继续原样保留引入路由面新增归一化的signal对象用于路由与去重友好过滤传输同构让 command / 原生网关与 HTTP 网关收到同一逻辑载荷结构。二、统一 Payload 结构HTTP 网关收到的 JSON 具有如下结构来自 文档 Payload shape 章节字段注释与实现对齐{ event: post-tool-use, instruction: ..., timestamp: 2026-03-09T00:00:00.000Z, sessionId: ..., projectPath: ..., projectName: ..., tmuxSession: ..., tmuxTail: ..., signal: { kind: test, name: test-run, phase: failed, routeKey: test.failed, priority: high, toolName: Bash, command: pnpm test, testRunner: package-test, summary: FAIL src/example.test.ts | ... }, context: { sessionId: ..., projectPath: ..., toolName: Bash } }在源码层面该结构的类型定义位于 src/openclaw/types.ts其中OpenClawPayloadL111-L139定义了event / instruction / timestamp / sessionId / projectPath / projectName / tmuxSession / tmuxTail / channel / to / threadId / signal / context等字段。需要特别说明的两个安全设计channel、to、threadId来自OPENCLAW_REPLY_CHANNEL / OPENCLAW_REPLY_TARGET / OPENCLAW_REPLY_THREAD环境变量用于支持 Discord 等渠道的回执路由。context是白名单子集见 src/openclaw/index.ts 中的buildWhitelistedContext仅显式挑选已知字段拼装杜绝敏感数据外泄。三、signal契约详解signal是本次契约的核心新增面字段语义见 文档信号字段表对应 TypeScript 类型为 src/openclaw/types.ts 中的OpenClawSignalKind / OpenClawSignalPhase / OpenClawSignalPriority / OpenClawSignalL66-L109。字段含义允许取值源码中的联合类型kind路由家族Routing familysession、tool、test、pull-request、question、keywordname稳定的逻辑信号名如session、tool-use、test-run、pull-request-create、ask-user-question、keyword-detectedphase生命周期阶段started、finished、failed、idle、detected、requestedrouteKey供下游消费者使用的规范化路由键详见下文高优先级 route keypriority相对优先级high运维型信号生命周期/测试/PR/提问、low一般工具噪音除上表字段外signal 在适用场景下还可能携带以下附加字段文档 Additional fieldstoolName—— 触发的工具名如Bash、Edit、Writecommand—— 触发路由判断的 Bash 命令原文testRunner—— 归一化后的测试运行器标识prUrl—— 从gh pr create输出中提取的 PR 链接summary—— 用于路由与调试的短摘要3.1 signal 是如何从原始事件推导出来的所有signal均由 src/openclaw/signal.ts 中的buildOpenClawSignal(event, context)依据事件类型分派生成各 hook 事件到 signal 的映射为session-start→{ kind: session, phase: started, routeKey: session.started, priority: high }session-end→{ kind: session, phase: finished, routeKey: session.finished, priority: high }并用context.reason生成 summarystop→{ kind: session, phase: idle, routeKey: session.idle, priority: high }keyword-detector即UserPromptSubmitbridge 面→{ kind: keyword, routeKey: keyword.detected, priority: low }ask-user-question→{ kind: question, routeKey: question.requested, priority: high }pre-tool-use/post-tool-use→ 走buildToolSignal见下未识别事件兜底 →{ kind: tool, routeKey: tool.finished, priority: low }值得关注的是buildToolSignal内嵌的启发式判定逻辑src/openclaw/signal.ts#L124-L173它把原始工具输入输出升华为语义信号测试命令识别当 Bash 命令命中测试模式表L8-L16时升级为kind: test信号。该表内置了package-testnpm/pnpm/yarn/bun test、vitest、jest、pytest、cargo-test、go-test、make-test共 7 类运行器并填充testRunner字段。PR 创建识别当命令匹配gh pr create时升级为kind: pull-request信号并尝试从输出中提取 GitHub PR URL正则见 L5-L6phase 决定 routeKey 是pull-request.started/pull-request.failed/pull-request.created。工具成败判定Bash 按输出内容特征error:、failed、FAIL、exit code: [1-9]、permission denied、fatal:等L46-L63判断finished/failedEdit/Write则按写失败特征write failed、read-only、no such file等判断。普通工具成功即tool.finishedpriority: low失败即tool.failedpriority: high。噪音清理会剥离 Claude 临时目录的permission denied .../T/claude-*-cwd报错、Error: Exit code N前缀等已知噪音L3-L4。摘要压缩summarize将输出压缩为最多 4 行、160 字符的单行摘要L92-L105。四、原生 command 网关契约docs/OPENCLAW-ROUTING.md明确规定command 网关通过两种通道获得与 HTTP 网关完全相同的归一化载荷。模板变量{{payloadJson}}—— 完整归一化 payload 的 JSON 序列化串。环境变量OPENCLAW_PAYLOAD_JSON—— 与上述同源的完整 JSON。同时还会收到三个便于轻量路由的便捷环境变量OPENCLAW_SIGNAL_ROUTE_KEY如test.failedOPENCLAW_SIGNAL_PHASE如failedOPENCLAW_SIGNAL_KIND如test这意味着无论传输层是 HTTP 还是 shell 命令原生 Clawhip 路由都只面对同一套契约文档 Native command gateway contract。从实现看command 网关的唤起由 src/openclaw/dispatcher.ts 的wakeCommandGateway完成L143-L187模板中的{{variable}}占位符在插值前会经过shellEscapeArg单引号包裹转义L83-L85防止命令注入命令通过sh -c以execFile异步执行非阻塞、带超时默认 10s上述四个环境变量正是在此注入子进程 envL168-L176。同理HTTP 网关由wakeGatewayL90-L135唤起并内置 URL 校验规则必须 HTTPS仅localhost/127.0.0.1/::1允许明文 HTTP便于本地开发。五、当前高优先级 route key 清单文档明确列出的现役高优先级 route key如下文档清单session.startedsession.finishedsession.idlequestion.requestedtest.startedtest.finishedtest.failedpull-request.startedpull-request.createdpull-request.failedtool.failed而通用的tool.started/tool.finished保留为低优先级兜底信号src/openclaw/signal.ts#L164-L172 中tool分支仅失败时priority升为high。keyword.detected同样是低优先级信号适用于提示已提交但无需运维介入的场景。5.1 路由键与优先级对齐源码signal 的kind/name/phase/routeKey/priority五个字段在 src/openclaw/signal.ts 的各分支中一一落地。整体规律可归纳为routeKey {kind}.{phase}如test.failed特殊场景使用语义化子键如pull-request.created凡是生命周期、测试、PR、提问信号一律priority: high普通工具过程信号为low。这与文档 Stability notes 中消费者应优先过滤signal.priority high或显式匹配signal.routeKey而不是直接在裸 hook 名上路由的建议完全一致。六、噪音抑制Noise Reduction高频事件天然会产生流量噪音。文档给出三层抑制手段文档 Noise reduction底层由 src/openclaw/dedupe.ts 的shouldCollapseOpenClawBurst实现AskUserQuestion 只发专用信号ask-user-question现在只发出question.requested信号不再叠加发射通用工具生命周期事件避免下游被同一条提问刷屏src/openclaw/signal.ts#L211-L219。attached-tmux 生命周期突发折叠OpenClaw 在派发前会对重复的 tmux 会话生命周期突发做折叠collapse折叠维度统一为{projectPath, tmuxSession}源码键形如session.started::{projectPath}::{tmuxSession}各类事件的具体窗口为事件面折叠键窗口session-startsession.started::{scope}10 000 msSTART_WINDOW_MSkeyword-detectorprompt 提交突发session.prompt-submitted::{scope}::{sha1(prompt前12位)}4 000 msPROMPT_WINDOW_MSstopsession.stopped::{scope}12 000 msSTOP_WINDOW_MSsession-endsession.finished::{scope}12 000 msSTOP_WINDOW_MSkeyword 折叠会对 prompt 先做空白归一化并截断到 400 字符再取 SHA-1 摘要src/openclaw/dedupe.ts#L236-L242确保语义相同的连续提交被识别为重复。终端状态滞后抑制在stop/session-end之后60 秒TERMINAL_STATE_SUPPRESSION_WINDOW_MS内到达的滞后session-start、stop事件会被判定为过期isObsoleteAfterTerminalStatesrc/openclaw/dedupe.ts#L314-L341而丢弃用于吸收子进程启动延迟、detach/re-attach 时序造成的 hook 乱序。去重状态采用磁盘持久化 进程锁实现状态记录写入项目目录下.omc/state/openclaw-event-dedupe.json原子写锁文件.omc/state/openclaw-event-dedupe.lock带 pid 随机 token支持 2s 获取超时、20ms 重试、10s 陈旧锁清理与 6 小时状态 TTL 修剪src/openclaw/dedupe.ts#L23-L41。被折叠的事件在唤起结果中会以skipped: deduped标记src/openclaw/types.ts#L171-L182。七、稳定性与兼容性说明文档 Stability notes 确立了三条兼容红线文档章节在源码中均有对应约束原始event名称完全保留用于向后兼容 ——OpenClawPayload.event仍携带裸 hook 名旧消费者无需迁移即可继续工作。signal是新建原生 Clawhip 集成的首选路由面—— 字段有严格联合类型约束src/openclaw/types.ts#L66-L109并在生成阶段集中推导保证所有网关收到的 signal 形状一致。context是白名单子集内部原始工具输入/输出toolInput/toolOutput只用于推导归一化 signal绝不进入payload.contextsrc/openclaw/types.ts#L147-L168 的注释明确此点从类型层杜绝敏感数据随事件外发。八、集成接入要点与配置若要实际启用 OpenClaw 网关需结合 README.md OpenClaw Integration 章节 完成三步启用开关设置环境变量OMC_OPENCLAW1配置读取器在 src/openclaw/config.ts 中会先校验该开关未开启直接返回null保证零开销。编写配置文件~/.claude/omc_config.openclaw.json示意结构如下{ enabled: true, gateways: { my-gateway: { url: https://your-gateway.example.com/wake, headers: { Authorization: Bearer YOUR_TOKEN }, method: POST, timeout: 10000 } }, hooks: { session-start: { gateway: my-gateway, instruction: Session started for {{projectName}}, enabled: true }, post-tool-use: { gateway: my-gateway, instruction: {{payloadJson}}, enabled: true } } }若网关配置为命令型需把 gateway 改为type: command并提供command模板其中instruction可引用{{payloadJson}}在内的全套模板变量。配置文件路径也可通过OMC_OPENCLAW_CONFIG覆盖OMC_OPENCLAW_DEBUG1可开启调试日志。相关类型定义集中在 src/openclaw/types.ts 的OpenClawConfig / OpenClawGatewayConfig / OpenClawHookMapping。观察事件流桥接层的实际唤起点位于 src/hooks/bridge.ts通过_openclaw.wake(...)分别在keyword-detectorL1654、stopL1876、session-startL1979、ask-user-questionL2542、pre-tool-useL2760、post-tool-useL2994等事件触发bridge.ts L2308-L2317 定义了该可测试包装器。主入口wakeOpenClawsrc/openclaw/index.ts#L75-L209负责串联读取配置 → 解析事件映射 → 构建 signal → 突发折叠判断 → 自动捕获 tmux 尾部输出 → 构造模板变量与 payload → 按网关类型唤起。参考网关实现见 scripts/openclaw-gateway-demo.mjs。8.1 事件到信号的关键模板变量桥接层为每个模板插值准备了丰富变量src/openclaw/index.ts#L140-L165除{{payloadJson}}与{{instruction}}外还包括会话维度{{sessionId}}、{{projectPath}}、{{projectName}}、{{tmuxSession}}、{{timestamp}}signal 维度{{signalKind}}、{{signalName}}、{{signalPhase}}、{{signalRouteKey}}、{{signalPriority}}、{{signalSummary}}上下文维度{{toolName}}、{{prompt}}、{{contextSummary}}、{{question}}、{{reason}}、{{tmuxTail}}、{{command}}、{{testRunner}}、{{prUrl}}回执维度{{replyChannel}}、{{replyTarget}}、{{replyThread}}需要留意HTTP 网关的 instruction 由interpolateInstruction处理未解析的变量会原样保留而非替换为空src/openclaw/dispatcher.ts#L60-L67而 command 网关模板中的变量则统一走 shell 转义见前文二者语义略有差异。九、消费端路由建议与小结基于上述契约原生 Clawhip 消费者在接入时应遵循以下最佳实践首选signal.routeKey做精确路由例如订阅test.failed以触发失败告警、订阅pull-request.created触发 PR 通知次选signal.priority high做通配过滤将tool.started/tool.finished等低优先级噪音天然挡在门外不要直接依赖裸 hook 名如post-tool-use做业务分发因为同一 hook 名可能承载多种逻辑语义只有 signal 才是归一化后的语义真相对会话维度事件注意突发折叠语义session-start/stop/session-end及 prompt 提交会按{projectPath, tmuxSession}做窗口去重接收端无需重复实现幂等。总体上oh-my-claudecode 的 OpenClaw/Clawhip 路由契约是一套兼顾**向后兼容保留 event、向前演进新增 signal与传输同构HTTP/command 共享 payload**的三层设计。它把「会话、工具、测试、PR、提问、关键词」六大信号家族收敛到统一字段语义与 route key 空间让下游消费者无论走 HTTP 还是原生 shell 命令都能用同一套逻辑完成路由、过滤与去重 —— 这也正是docs/OPENCLAW-ROUTING.md作为集成契约文档的全部价值所在。【免费下载链接】oh-my-claudecodeTeams-first Multi-agent orchestration for Claude Code项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-claudecode创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表