在 Harness 中,插件是一个导出 apply 函数的 TypeScript 模块。框架加载插件时调用 apply,并传入 ctx(上下文对象)。
ctx(Context) 是框架传给每个插件的上下文对象,既是注册能力的入口(事件监听、工具、LLM 适配器),也记录了插件注册的一切资源。
最小插件:hello-plugin
1// 文件路径:scratch-plugin/src/my-plugin.ts
2import type { Context } from '@deepseek-ai/cordis'
3
4// name 是插件名,用于在日志与配置中标识这个插件
5export const name = 'hello-plugin'
6
7// apply 是插件的入口:框架加载插件时调用它
8export function apply(ctx: Context) {
9 // 需要的依赖在 apply 执行前就已就绪
10 console.log('[hello-plugin] plugin loaded!')
11}
这段代码只做一件事:加载时打印一行日志,没有注册任何能力,但已经是一个合格的插件。
插件的三种形态
| 形态 | 写法 | 适用场景 |
|---|---|---|
| 函数形式 | 导出独立的 apply 函数 | 大多数插件,最简单直接 |
| 对象形式 | export default 一个带 name / inject / apply 的对象 | 需要同时声明元信息时 |
| 类形式 | export default 一个 Service 子类 | 插件需要向其他插件提供服务时 |
函数形式
1import type { Context } from '@deepseek-ai/cordis'
2
3export const name = 'my-plugin'
4
5export function apply(ctx: Context) {
6 // 在这里注册能力
7}
对象形式
1import type { Context } from '@deepseek-ai/cordis'
2
3export default {
4 name: 'my-plugin',
5 inject: ['tools'],
6 apply(ctx: Context) {
7 // ...
8 },
9}
类形式
1import { Service, type Context } from '@deepseek-ai/cordis'
2
3export default class MyService extends Service {
4 static inject = ['tools']
5
6 constructor(ctx: Context) {
7 // 第一个参数是 ctx,第二个参数是服务名
8 super(ctx, 'myService')
9 // 同步初始化放在构造函数里
10 }
11}
怎么选
大多数情况下,函数形式就足够了。当插件需要向其他插件提供服务时,用类形式。类形式的核心是 super(ctx, '服务名')。
服务与依赖的完整机制见 Service 基类与类型声明 和 inject 声明依赖。