DeepSeek Harness 插件生命周期 Fiber

2026-09-08 00:00    #AI   #工具   #DeepSeek  

Fiber 是什么

每个被加载的插件都拥有一个 Fiber 作用域,是插件实例的执行单元,承载插件从声明、加载、运行到卸载的全部状态。

Fiber:一个插件实例在 Cordis 运行时中的状态容器。它记录该插件的生命周期状态,也是卸载时清理注册的依据。

Fiber 状态机

主路径:PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED;在 LOADING 阶段如果 apply 抛出异常,则进入 FAILED。

状态含义发生时机
PENDING已声明,但所需依赖未就绪插件被加入上下文,inject 的服务还没准备好
LOADING依赖就绪,正在执行 apply所有必需服务就绪,框架调用 apply(ctx)
ACTIVE插件运行中apply 正常返回,注册生效
FAILEDapply 抛出异常apply 执行过程中抛错,加载失败
UNLOADING插件正在卸载并释放资源依赖消失、被 dispose、或 HMR 触发卸载
DISPOSED已完全卸载所有处置器执行完毕

依赖驱动的加载

1// 文件路径:scratch-plugin/src/my-plugin.ts
2// 声明本插件需要 tools 与 llm 两个服务,二者就绪前 apply 不会执行
3export const inject = ['tools', 'llm']
4
5export function apply(ctx: Context) {
6  // 走到这里时,ctx.tools 和 ctx.llm 一定已经就绪
7}

这是 Cordis 用服务依赖来表达加载顺序的方式,而不是手动编排启动序列。

自动清理机制

通过 ctx 做的任何注册,卸载时自动撤销:

注册操作卸载时的清理
ctx.on(event, handler)事件监听自动移除
ctx.tools.register(tool)工具注册自动移除
ctx.llm.registerAdapter(names, adapter)LLM 适配器注册自动移除
ctx.effect(() => cleanup)返回的处置器在卸载时执行

处置器的调用顺序

动手示例:观察状态迁移

 1// 文件路径:scratch-plugin/src/lifecycle-log.ts
 2export function apply(ctx: Context) {
 3  // apply 被调用:插件从 LOADING 进入 ACTIVE
 4  console.log('runoob plugin loading')
 5
 6  // 注册一个效果:返回的清理函数在卸载时执行
 7  ctx.effect(() => {
 8    console.log('runoob effect registered')
 9    // 返回 disposer:插件卸载时调用
10    return () => console.log('runoob effect cleaned up')
11  })
12}

加载时输出:

1runoob plugin loading
2runoob effect registered

卸载时输出:

1runoob effect cleaned up

可以看到 apply 先执行,随后执行到 effect 注册,返回的处置器在卸载阶段被调用。

自测

  1. Fiber 有哪六个状态?apply 抛异常时进入哪个状态?→ 六个;FAILED
  2. 为什么 ctx.on 注册的监听器不需要手动 removeListener?→ 自动清理
  3. 两个存在顺序依赖的清理步骤,应该怎么写才安全?→ 放进同一个 ctx.effect()