Host 服务与事件
Host 侧开发:用 ctx.get 读取可选服务、用 inject 声明硬依赖、监听事件、提供服务
Host 是插件运行的 Node.js 进程侧。在这里读写服务、监听事件、向其他插件提供服务。
什么是服务
服务是一个插件向其他插件公开的能力。tools、llm、agents 都是挂载在 ctx 上的命名服务:
ctx.tools // 工具运行时服务
ctx.llm // LLM 服务
ctx.agents // Agent 服务任何插件都可以提供服务供其他插件使用。
读取服务
硬依赖:inject
声明 inject 使用必需服务。apply 执行时,这些服务已经全部就绪;若服务缺失,插件会等待而非运行:
export const inject = ['tools']
export function apply(ctx: Context) {
// ctx.tools 在这里已就绪。
ctx.tools.register(/* ... */)
}可选依赖:ctx.get
可选服务不写进 inject,在使用处用 ctx.get() 查询并处理 undefined:
export function apply(ctx: Context) {
const metrics = ctx.get('metrics')
metrics?.record('plugin_loaded', 1)
}服务消失时
若必需服务在运行期间消失(例如其提供方卸载):依赖它的插件会自动 dispose(资源释放),服务重新出现时自动重新加载。这防止插件调用已不存在的服务。
提供服务
继承 Service 基类:
import { Service, type Context } from '@deepseek-ai/cordis'
export default class MetricsService extends Service {
static inject = ['llm']
constructor(ctx: Context) {
super(ctx, 'metrics')
}
record(event: string, value: number) {
// ...
}
}加载后,消费方通过 ctx.metrics 访问它。用 TypeScript 声明合并为 ctx.metrics 提供类型;服务名、公开方法与源码位置以各能力子系统的生成文档为准。
监听事件
用 ctx.on() 监听,用 ctx.emit() 触发:
ctx.on('tools/result', handler) // 插件卸载时自动移除
ctx.emit('my-plugin/ready', payload)事件具有不同的分发模式:
emit— 广播:所有监听器同步执行,返回值被忽略。bail— 短路:按序运行,第一个非null、false、undefined的返回值成为最终结果。serial— 顺序执行:按序执行并等待异步结果,首个非空结果终止后续执行。waterfall(瀑布式事件)— 流水线:每个监听器可包装下游结果;必须调用next()委托下游,不调用即短路。
waterfall 必须 next()
waterfall 监听器必须调用 next()。不调用会短路整个流水线——这是拦截/网关行为的设计意图。
Cordis 事件与会话记录
turn/*、step/*、tool/call、tool/result 是持久会话事件类型,不是同名 Cordis 事件。要观察它们,监听 session/event 并检查 event.type。
事件监听器也是 effect
通过 ctx.on() 注册的监听器在插件卸载时自动移除;所有注册都属于当前 fiber 的生命周期。需要显式清理的资源(如网络连接)用 ctx.effect() 返回 disposer:
export function apply(ctx: Context) {
ctx.effect(() => {
const connection = createConnection()
return () => connection.close()
})
}下一步
- 在浏览器侧注册 UI,见 Client UI 与 Slot。
- 注册面向模型的工具,见 注册模型工具。