# 第一个插件 [English](index.md) | 中文 本文带你编写一个最小的 Harness 插件并加载到 agent(智能体)中。 ## 插件是什么 在 Harness 中,插件是一个导出 `apply` 函数的 TypeScript 模块。框架在加载时调用 `apply`,传入一个 `ctx`(上下文对象),你通过 `ctx` 注册能力: ```ts import type { Context } from 'cordis' export const name = 'my-plugin' export function apply(ctx: Context) { // Register capabilities here. } ``` 这就是完整结构。 ## 创建插件文件 在你的项目目录下创建 `src/my-plugin.ts`: ```ts import type { Context } from 'cordis' export const name = 'hello-plugin' export function apply(ctx: Context) { // Required dependencies are ready before apply runs. console.log('[hello-plugin] plugin loaded!') } ``` ## 注册到 cordis.yml 在你的 `cordis.yml` 中添加一条: ```yaml - id: hello name: './src/my-plugin.ts' ``` 启动后你会在控制台看到 `[hello-plugin] plugin loaded!`。 ## 自动清理 通过 `ctx` 注册的任何东西——事件监听、工具、定时器——在插件卸载时都会被自动清理。你不需要手动 removeListener 或 clearInterval。 如果你有需要手动清理的资源(比如一个网络连接),用 `ctx.effect()` 告诉框架怎么清理: ```ts import type { Context } from 'cordis' export function apply(ctx: Context) { ctx.effect(() => { const timer = setInterval(() => { console.log('heartbeat') }, 5000) // The returned function runs when the plugin unloads. return () => clearInterval(timer) }) } ``` ## 声明依赖 如果你的插件需要使用其他服务(如 `tools`、`llm`),需要声明 `inject`: ```ts ignore-check import type { Context } from 'cordis' export const name = 'my-tool-plugin' export const inject = ['tools'] export function apply(ctx: Context) { // ctx.tools is ready here. ctx.tools.register(/* ... */) } ``` 框架会确保依赖的服务就绪后才加载你的插件。 ## 插件的三种形态 除了函数形式,插件还支持对象形式和类形式: ### 对象形式 ```ts import type { Context } from 'cordis' export default { name: 'my-plugin', inject: ['tools'], apply(ctx: Context) { // ... }, } ``` ### 类形式 ```ts import { Service, type Context } from 'cordis' export default class MyService extends Service { static inject = ['tools'] constructor(ctx: Context) { super(ctx, 'myService') // Perform synchronous initialization in the constructor. } } ``` 大多数情况下,函数形式足够了。当插件需要向其他插件提供服务时,可使用类形式(见 [服务与依赖](../framework/service.md))。 ## 完整示例 最小的工具插件会在 `ctx.tools` 上注册其定义: ```ts import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' export const name = 'greet-tool' export const inject = ['tools'] export function apply(ctx: Context) { ctx.tools.register(defineTool({ name: 'greet', description: 'Greet the named person.', parameters: { name: { type: 'string', required: true }, }, output: { schema: { type: 'string' }, render: (_args, value) => [{ type: 'text', text: value }], }, async execute(args) { return `Hello, ${args.name}!` }, })) } ``` ## 下一步 - [开发一个工具](./tool.md) — 详细了解工具定义 DSL - [插件配置](./config.md) — 让插件接受用户配置