DeepSeek Harness 蓝皮书
开发者指南

Host 服务与事件

Host 侧开发:用 ctx.get 读取可选服务、用 inject 声明硬依赖、监听事件、提供服务

Host 是插件运行的 Node.js 进程侧。在这里读写服务、监听事件、向其他插件提供服务。

什么是服务

服务是一个插件向其他插件公开的能力。toolsllmagents 都是挂载在 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 — 短路:按序运行,第一个非 nullfalseundefined 的返回值成为最终结果。
  • serial — 顺序执行:按序执行并等待异步结果,首个非空结果终止后续执行。
  • waterfall(瀑布式事件)— 流水线:每个监听器可包装下游结果;必须调用 next() 委托下游,不调用即短路。

waterfall 必须 next()

waterfall 监听器必须调用 next()。不调用会短路整个流水线——这是拦截/网关行为的设计意图。

Cordis 事件与会话记录

turn/*step/*tool/calltool/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()
  })
}

下一步

本页目录