肆 · 通知

通知渠道

ctx.notify

与渠道无关的通知:业务包只调用 ctx.notify.send(),同一时间发往一个渠道(钉钉或飞书)。渠道由配置决定,也可以在运行中用 ctx.notify.use() 切换,不需要改业务代码。

接口

const r = await ctx.notify.send({
  title: '需要人工复核',
  markdown: '## 详情\n...',              // 或 text: '纯文本',二选一
  targets: {                             // 可选,按渠道给出目标,发送时只用当前渠道那一项;缺省用该渠道的 defaultTarget
    dingtalk: { chatId: 'cid...' },
    feishu: { chatId: 'oc_...' },
  },
  at: {                                  // 可选,按渠道 @ 人(两边的用户 id 体系不同)
    dingtalk: { userIds: ['...'] },
    feishu: { userIds: ['ou_...'] },
  },
  idempotencyKey: 'evt_...',             // 透传给渠道
  traceId: 'evt_...',
  signal,
})
// r: { channel: 'dingtalk' | 'feishu', results: Array<{ ok, messageId?, error? }> }

业务包只需要 inject = ['notify']。发往哪个渠道由本行的配置决定:

- id: agent-kit-notify
  disabled: false
  config:
    channel: feishu   # dingtalk 或 feishu;对应的渠道行需要启用

发送结果与错误

切换渠道

方式何时生效持续多久
修改配置的 channel(手动编辑 cordis.patch.yml,或 admin 包的设置页 / setup)保存后立即,原地生效长期;覆盖此前 use() 的选择
ctx.notify.use('feishu')调用后立即只在内存中;dsh 重启后回到配置值,期间修改配置时以新配置为准
ctx.notify.channel          // 当前生效的渠道:'dingtalk' | 'feishu'
ctx.notify.use('dingtalk')  // 运行中切换;传入其他值抛出 NotifyError(code: invalid_channel)

要长期切换请改配置;use() 适合业务包自己的临时逻辑,例如当前渠道登录失效时先改用另一个渠道。

登录状态与登录

const s = await ctx.notify.status()
// {
//   channel: 'feishu',
//   source: 'config',                     // 'config':来自配置;'runtime':被 use() 切换过
//   channels: {
//     feishu: { channel: 'feishu', running: true, identity: 'user', online: false, detail: '…', checkedAt: 1758… },
//     dingtalk: { channel: 'dingtalk', running: false, detail: 'agent-kit-dingtalk is not running' },
//   },
// }

login() 是设备流登录:拿到授权链接就返回,链接怎么交给要登录的人由业务包决定。例如发到运维群:

const s = await ctx.notify.login()                   // 当前渠道
await postToOps(`请在 15 分钟内打开链接完成登录:${s.verificationUrl}`)
const st = await s.completed                         // 授权完成后的状态;过期、拒绝或 s.cancel() 时 online 为 false

渠道与生命周期

本 Service 不 inject 钉钉与飞书,而是在每次发送时查找对应的 Service。原因是 cordis 4 的 inject 都是必需的:如果 notify inject 了渠道,停用任一渠道都会连带卸载 notify,以及所有只依赖 notify 的业务插件。

现在的行为是:

什么时候直接用 ctx.dingtalk 或 ctx.feishu

需要某个渠道特有的能力时,例如钉钉的 openDingtalkId 目标或 webhook 身份,直接 inject 对应的 Service。只是「发一条通知」时,推荐用 ctx.notify,把渠道选择留给运维。

配置

在 Profile 的 cordis.patch.yml 中按 id agent-kit-notify 启用并给出配置。按 id 修改 config 时整段替换,未给出的字段使用默认值。下表由本包源码中的配置 schema 生成。

- id: agent-kit-notify
  disabled: false
  config:
    # 只写需要改的字段,其余使用下表的默认值
字段默认值取值范围说明
channel 必填 — dingtalk | feishu 通知发往的渠道:dingtalk 或 feishu

约束与说明

错误码

所有错误都是 KitError:用 isKitError(e) 判断,按 code 与 retryable 决定是否重试。

code可重试含义
channel_unavailable 否 当前渠道(或 login() / logout() 指定的渠道)对应的行未运行(未启用或启动失败);details.channel 为渠道名。
invalid_channel 否 use() 传入了 dingtalk / feishu 以外的渠道。
invalid_config 否 配置或环境变量非法,Service 启动失败。