ctx.emit(name, ...args)同步广播给全部监听器。返回值和 Promise 都不会被等待或收集。
松耦合通知与协作决策
事件把插件解耦,同时用明确的分发模式约束广播、顺序、并发和拦截。
declare module '@deepseek-ai/cordis' {
interface Events {
'stats/report'(name: string, count: number): void
}
}
ctx.on('stats/report', (name, count) => {
console.log(`[stats] ${name} -> ${count}`)
})
ctx.emit('stats/report', 'tool_call', 1)
interface Events 声明合并让 ctx.emit 与 ctx.on 同时获得参数和返回值类型。它不会产生运行时代码。
stats/reportnamespace/action 让扁平命名空间保持可读import type {} from './stats.ts'只让 TypeScript 看到声明合并,不产生运行时导入ctx.on(name, listener)监听器属于当前 Fiber,卸载时自动移除模式是事件公开契约的一部分。开发时应以所属子系统页面生成的 cordis-surface 区块为准。
ctx.emit(name, ...args)同步广播给全部监听器。返回值和 Promise 都不会被等待或收集。
await ctx.parallel(name, ...args)所有监听器并发运行,调用方等待它们全部完成。
await ctx.serial(name, ...args)按注册顺序等待。第一个有效返回值胜出并停止后续监听器。
ctx.bail(name, ...args)serial 的同步版本。null、false 和 undefined 表示继续。
ctx.waterfall(name, ...args, next)每层可以包装下游结果,也可以不调用 next() 来主动短路。
第一个不是 null、false 或 undefined 的结果成为最终值。零、空字符串和 true 都会停止后续监听器。
监听器调用 next() 进入下游,再在返回路径上转换结果。不调用 next() 就代表当前监听器接管决定。
ctx.on('demo/transform', async (input, next) => {
const downstream = await next()
return downstream.toUpperCase()
})
ctx.on('demo/transform', async (input, next) => {
if (input.includes('blocked')) return '** blocked **'
return next()
})日志监听器忘记 next() 会静默吞掉所有下游默认行为。不调用只能用于有意的拦截、网关或否决。
agent/request插件可以替换模型调用配置approval/request策略可以代替用户回答审批名字相似不代表可以直接 ctx.on。先判断目标属于运行时通信还是会话历史。
agent/stepagent/requesttools/resultsession/event直接按官方签名监听turn/*step/*tool/calltool/resultcompaction/*监听 session/event,再检查 event.type监听器属于当前 Fiber 的 effect。卸载、热替换或依赖消失时,无需手工 removeListener。
export function apply(ctx: Context) {
ctx.on('tools/result', (exec, result) => {
console.log(`[tool] ${exec.name}`)
const text = result.content
.map(block => block.type === 'text' ? block.text : '')
.join('')
console.log(`[tool result] ${text.slice(0, 100)}`)
})
}