$dshubuser@dshub:~/plugins$
  • 插件
  • 提交插件
  • 博客
事件:不知道谁在听,也能让插件协作
2026/08/25

事件:不知道谁在听,也能让插件协作

从类型化事件和五种分发模式出发,理解 Cordis 如何让服务广播事实、并发工作或交出决策。

核心区别:服务适合直接调用,事件适合通知未知消费者;事件模式则明确规定等待、返回值与短路行为。

插件不需要知道“现在有几个监听器”。它只需要发出一个有类型的事件,其他插件在自己的生命周期里订阅它。

01 / 声明一个有类型的事件

Cordis event sender and independent listeners connected through a typed event name
import type { Context } from '@deepseek-ai/cordis'

declare module '@deepseek-ai/cordis' {
  interface Events {
    'stats/report'(name: string, count: number): void
  }
}

export function report(ctx: Context) {
  ctx.emit('stats/report', 'tool_call', 1)
}

声明合并让 ctx.emit 和 ctx.on 知道事件名称与 payload。它不会生成运行时代码;运行时连接仍然来自 emitter 和 listener 的注册。

监听器可以来自完全不同的插件:

ctx.on('stats/report', (name, count) => {
  console.log('[stats] ' + name + ' -> ' + count)
})

ctx.on() 是当前 Fiber 的 effect,监听器会随插件卸载,不需要手动保存 removeListener。

02 / 五种模式是公开语义

Cordis event dispatch modes comparing emit parallel serial bail and waterfall
模式调用语义
emitctx.emit同步分发,忽略监听器返回值
parallelawait ctx.parallel并发运行所有监听器,并等待全部结束
serialawait ctx.serial按顺序等待,首个非 null/false/undefined 结果胜出
bailctx.bailserial 的同步版本
waterfallctx.waterfall监听器通过 next() 包装下游

失败行为也属于模式语义:emit 不会等待 listener 返回的 promise,但 listener 的同步异常会从调用方抛出;parallel 会等待所有 listener,并在任一 listener 拒绝时抛出 AggregateError;serial、bail 和 waterfall 不会吞掉 listener 异常。

事件的调用方不能随意换模式。模式是事件公开约定的一部分,应该在事件声明或所属子系统文档中明确。

03 / 事件和服务如何分工

服务适合直接请求一个能力,例如 ctx.tools.register() 或 ctx.sessions.fork()。事件适合把事实或请求交给多个独立扩展点:

  • 持久事实通过 session/event 广播给观察者。
  • Agent 运行中的协调使用 agent/* 事件。
  • 工具执行流水线使用 tools/* 事件。

如果事实必须在 reload 后重建,就让它进入 session log;仅仅发一个临时事件不能替代持久记录。

04 / 一个统计服务的完整路径

import { Service, type Context } from '@deepseek-ai/cordis'

export class StatsService extends Service {
  constructor(ctx: Context) {
    super(ctx, 'stats')
  }

  private counts = new Map<string, number>()

  bump(name: string) {
    const next = (this.counts.get(name) ?? 0) + 1
    this.counts.set(name, next)
    this.ctx.emit('stats/report', name, next)
  }
}

Provider 只负责更新计数和发出事件。Reporter 只负责监听和输出。两者的连接点是 stats/report,而不是彼此的文件路径。

下一步

  • waterfall:拦截与短路
  • 服务与上下文:共享能力
  • Cordis 在 DeepSeek Harness 里

来源:事件教程、Cordis Events 实现、Harness 架构中的事件域。

全部文章

作者

avatar for DSH Research
DSH Research

分类

  • Agent 基础设施
01 / 声明一个有类型的事件02 / 五种模式是公开语义03 / 事件和服务如何分工04 / 一个统计服务的完整路径下一步

更多文章

生命周期与 effect:让 Cordis 注册可以回卷
Agent 基础设施

生命周期与 effect:让 Cordis 注册可以回卷

跟随 Fiber 从 PENDING 到 DISPOSED,理解 effect、disposer 与 HMR 如何共同管理插件副作用。

avatar for DSH Research
DSH Research
2026/08/24
服务与上下文:Cordis 如何共享能力而不绑定实现
Agent 基础设施

服务与上下文:Cordis 如何共享能力而不绑定实现

从 Service、Context 与声明合并出发,理解提供者、消费者和作用域如何连接 DeepSeek Harness 的能力。

avatar for DSH Research
DSH Research
2026/08/22
waterfall:用 next() 做拦截、包装与短路
Agent 基础设施

waterfall:用 next() 做拦截、包装与短路

沿着一条真实的 Cordis waterfall 链路,理解监听器如何委托下游、包装结果,或在拥有决策权时直接短路。

avatar for DSH Research
DSH Research
2026/08/26

邮件列表

加入我们的社区

订阅邮件列表,及时获取最新消息和更新

[dshub] [zsh]$ dshub ls$ dshub submit$ dshub blog
-- NORMAL -- ✓ 2026 dshub