事件:不知道谁在听,也能让插件协作
从类型化事件和五种分发模式出发,理解 Cordis 如何让服务广播事实、并发工作或交出决策。
核心区别:服务适合直接调用,事件适合通知未知消费者;事件模式则明确规定等待、返回值与短路行为。
插件不需要知道“现在有几个监听器”。它只需要发出一个有类型的事件,其他插件在自己的生命周期里订阅它。
01 / 声明一个有类型的事件
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 / 五种模式是公开语义
| 模式 | 调用 | 语义 |
|---|---|---|
emit | ctx.emit | 同步分发,忽略监听器返回值 |
parallel | await ctx.parallel | 并发运行所有监听器,并等待全部结束 |
serial | await ctx.serial | 按顺序等待,首个非 null/false/undefined 结果胜出 |
bail | ctx.bail | serial 的同步版本 |
waterfall | ctx.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,而不是彼此的文件路径。
下一步
更多文章
生命周期与 effect:让 Cordis 注册可以回卷
跟随 Fiber 从 PENDING 到 DISPOSED,理解 effect、disposer 与 HMR 如何共同管理插件副作用。
服务与上下文:Cordis 如何共享能力而不绑定实现
从 Service、Context 与声明合并出发,理解提供者、消费者和作用域如何连接 DeepSeek Harness 的能力。
waterfall:用 next() 做拦截、包装与短路
沿着一条真实的 Cordis waterfall 链路,理解监听器如何委托下游、包装结果,或在拥有决策权时直接短路。
邮件列表
加入我们的社区
订阅邮件列表,及时获取最新消息和更新