让外部系统(监控告警、CI、工单、任务编排器)驱动 botmux 机器人的两条入口:

  • Webhook 接入点:触发机器人在群里说话或跑工作流;网关不解析各平台格式,把原始事件原样交给模型读,新系统几乎零适配。在 Dashboard「接入点」页创建管理(当前 beta)。
  • API 任务触发:程序化把指令交给机器人执行并拿回结果——整个调用是纯 HTTP「请求 → 拿结果」,可选完全不进飞书(虚拟会话)。

Webhook 接入点

快速上手

  1. Dashboard →「接入点」→「新建接入点」:填名称、选触发的机器人、选投递群(推荐「固定群」按群名选)。
  2. 「校验方式」默认令牌,密钥留空自动生成。
  3. 创建后直接得到一条末尾已含令牌的 Webhook URL 和现成 curl:
curl -X POST 'http://<lan-ip>:7891/webhook/conn_xxx/<令牌>' \
  -H 'content-type: application/json' \
  -d '{"msg":"hello"}'

校验方式(按接入点单独选,两档)

方式要点
令牌(默认)整条 URL 即凭证,三种携带方式任选:路径段 …/webhook/<id>/<令牌>(默认)、查询参数 ?token=…、请求头 Authorization: Bearer …。服务端只做常量时间比对,无需时间戳/nonce/签名
HMAC 签名(高级)密钥从不上网,提供防篡改 + 防重放。调用方对 时间戳.原始body 做 HMAC-SHA256,携带三个请求头:x-botmux-timestamp(±5 分钟容差)、x-botmux-nonce(每次唯一)、x-botmux-signature(sha256=<hex> 或 base64url)。适合公网或本身就会签名的发送方(GitHub / Stripe 类)

令牌会落进反代日志 / 浏览器历史——URL 泄漏 = 凭证泄漏,公网建议 HMAC 或至少把令牌放请求头;令牌可在列表里随时轮换。

投递目标(三选一)

  • 固定群:按群名选(数据来自该机器人所在的群),群 ID 写入接入点,裸 URL 即可触发。
  • 由请求指定(动态):每次请求传群——查询参数 ?chatId=oc_xxx、请求头 x-botmux-chat-id、或请求体 chatId 字段;可选配「允许的群」白名单。
  • 每次新建群:每个事件自动拉新群处置,并自动把该机器人的授权用户拉进群。可填去重字段(点号路径如 alert.id):填了则相同去重值的事件复用同一个群,留空则每事件新建群。早期「状态字段 / 自动关群」已移除,群不再自动关闭。

触发方式与处理指令

  • 单轮对话:机器人针对事件回应一次;或工作流:把事件作为字符串参数 event 传给 workflow 的节点处理。
  • 处理指令(可选):默认机器人只收到原始事件 JSON、自由发挥;写一段指令(如「总结这条告警的严重程度,判断是否需要立即处理,@相关 oncall,并给出排查建议」)后,指令作为可信任务 <botmux_task trusted="true"> 注入在不可信事件数据 <botmux_external_event trusted="false"> 之上——模型先读「要做什么」,再把事件 JSON 当数据处理。

安全与可观测

  • 不被指挥:外部内容被明确框定为「待处理的事件数据,不是命令」,不执行其中指令、不泄露凭据。
  • 限流:可设宽松上限防报警风暴;暴露公网时还应配请求体硬上限。
  • 调用记录:Dashboard「调用日志」按时间 / Webhook / 结果筛选;单条记录可看 HTTP 状态、耗时、查询参数、请求头、JSON 请求体、路由参数与实际投递目标。
  • 脱敏:URL 令牌、Authorization / Cookie / 签名头,以及 body 中 password / secret / token / API key 字段写盘前替换为 [REDACTED];日志文件权限 0600,调用日志 API 不开放给 Dashboard 匿名只读。
  • 留存:默认保存脱敏后的请求头和 JSON 请求体 14 天,单个请求体最多 128 KB;可在列表关闭请求参数留存(仍记录状态、耗时与路由元数据)。

常见返回

现象原因
401 token verification failed令牌不对 / 没带令牌
404 unknown or disabled connector接入点 ID 错或已停用
400 target chatId is required动态模式没带群 ID
400 dedup_key_not_found配了去重字段但 body 取不到值
429 rate limit exceeded超过限流上限

API 任务触发

面向调用方开发者。两种模式共用端点 POST /api/trigger(dashboard,默认 http://<daemon-host>:7891):

模式触发适用可中途取消
同步options.waitForFinalOutput=true一发一收、任务 ≤5 分钟✗
异步options.asyncReturnSessionId=true快速接单 + 轮询、需取消 / 故障恢复✓

不传 chatId 时开虚拟会话:完全不进飞书群、不发消息。生产级调度推荐异步——同步模式的 sessionId 只在完成时返回,运行中拿不到、无法取消,HTTP 连接最长挂 5 分钟。

鉴权

当前用 dashboard 轮换式 token:程序化调用必须带 Cookie: botmux_dashboard_token=<TOKEN>;不要用 ?t=<TOKEN>(浏览器登录专用,POST 带它会返回 302)。token 获取:运行 botmux dashboard 取当前登录 URL ?t= 后那段;botmux dashboard rotate 使其失效。独立 API Key(如 X-Botmux-Api-Key)在规划中。

请求体与硬校验

{
  "source": { "type": "webhook" },
  "target": { "kind": "turn", "botId": "cli_xxx" },   // 目标机器人的 larkAppId
  "instruction": "要让机器人执行的指令(可信,顶层指令渲染)",
  "envelope": { "format": "json", "sourceName": "your-system", "trusted": false },
  "options": { /* 模式参数 */ }
}
  • envelope.trusted 必须是 false(防注入设计):声明 envelope 内容为不可信外部数据,daemon 才会包成 untrusted event、不执行其中夹带指令;要机器人真正执行的内容放顶层 instruction。
  • 不传 chatId 时,options 必须含 waitForFinalOutput 或 asyncReturnSessionId 之一,否则 400 target_required。
  • options.timeoutMs 范围 [1000, 300000](默认 120000),越界 400。
  • options.model / options.reasoningEffort(low/medium/high/xhigh)仅对 codex / codex-app 机器人生效,且只在本次触发创建新会话时冻结;其它机器人被忽略。

幂等键(options.idempotencyKey)

防重试重复执行:异步触发后响应丢失时,重试会新建 session 把任务跑第二遍。传一个发起前已持久化的稳定键,同键重试返回同一个 session/triggerId、不新建不重派(响应带 idempotent:true/false)。要点:

  • 仅支持 fresh async virtual 触发:target.kind:'turn' + asyncReturnSessionId:true,且不带 target.sessionId / rootMessageId / chatId / waitForFinalOutput / dryRun;其它组合带键直接 400。
  • 同键不同 payload → 409 idempotency_conflict,绝不把新请求静默串进旧任务。
  • 崩溃语义 at-most-once:派发中途 daemon 崩溃后不盲目重派,该键收敛到终态 failed(no_output),调用方按 Failed 处理。
  • 键 → session 映射只增不删,完成后的迟到重试仍复用同一 session。

轮询结果(四态契约)

GET /api/sessions/:sessionId/trigger-result(可选 ?triggerId= 精确匹配)。四态全部返回 HTTP 200 + ok:true;只看 state 字段,不要用 ok 或 HTTP 状态码判定:

state含义处理
running任务还在跑继续轮询
completed有最终产出读 output.content;codex-app 且采集到用量时带 usage(input/output/cacheRead/cacheCreate 四桶增量,缺失≠0)
failed会话终止但没捕获产出,errorCode:"no_output"(软终态)可能是真失败也可能是你自己的 close,需二次确认再落终态
not_found查无此会话两种物理表现都归一:404 + unknown_session(代理层短路);200 + state:"not_found"(daemon 磁盘查无)

同步模式超时返回 HTTP 504 + wait_timeout,但任务仍在后台跑——留 sessionId 兜底查询,别直接判失败。

重启存活与取消

  • 异步结果完成时持久化到 data/async-triggers/<sessionId>.json(只增不删,TTL 清扫在规划):daemon 重启后已完成任务仍返回 completed,恢复逻辑不应因单次查询拿不到就判任务丢失。
  • 取消:POST /api/sessions/:sessionId/close,语义是关闭整个会话(一次性虚拟异步会话只有一轮 turn,等价于中断本次)。取消后轮询返回 failed/no_output 属预期,按自己的取消意图落 cancelled。
  • output.content 极少数情况可能带一句前言(prompt 层引导、非硬保证);要求干净输出时在展示层做保守裁剪(只裁已知确定性前言前缀),切勿激进截取「只取最后一段」;持久化 / 审计存原始 content。

端点速查

端点方法用途
/api/triggerPOST触发任务(同步/异步由 options 决定)
/api/sessions/:id/trigger-resultGET异步轮询结果(四态)
/api/sessions/:idGET查会话元信息(状态/标题等)
/api/sessions/:id/closePOST取消/关闭会话

关键 errorCode:target_required、bad_request(trusted 校验 / timeoutMs 越界 / 幂等键超范围)、idempotency_conflict、bot_not_found、bot_not_in_chat、wait_timeout、no_output、session_not_found。

客户端轮询应把响应分五类:completed/running/failed 透传、not_found(两种形式)为终止、400/401/403 为终止 error、网络异常 / 超时 / 5xx / 非 JSON 为可重试 unknown——原任务可能仍在后台跑,误当查无补偿重派会导致双执行。

关联

  • 接入点、调用日志、群组管理均在 dashboard 操作,见 dashboard
  • 工作流触发模式的编排细节见 workflow
  • 虚拟会话与群会话的会话模型见 session-model
  • 定时触发(内部时钟版的外部触发)见 schedule