dsh プラグイン開発
DeepSeek Harness(dsh)向けプラグインを開発します。dsh は Cordis ベースのエージェントフレームワークです。プラグインは apply(ctx: Context) をエクスポートする TypeScript モジュールであり、cordis.yml で構成します。
クイックリファレンス
プラグイン構造
import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-plugin'
export function apply(ctx: Context) { /* 機能を登録 */ }
3つの形式: 関数(デフォルト)、オブジェクト({ name, inject, apply })、クラス(extends Service — 他のプラグインにサービスを提供する場合のみ使用)。
依存関係: export const inject = ['tools', 'llm'] — フレームワークは、注入されたすべてのサービスが準備できるまでプラグインを PENDING 状態に保ちます。
自動クリーンアップ: ctx を通じて登録されたものはすべてエフェクトです — アンロード時に自動的にクリーンアップされます。カスタムリソース(タイマー、接続)の場合は、ctx.effect(() => { ... return () => cleanup }) でラップします。
子プラグイン: const fiber = ctx.plugin(childPlugin) — 子は親コンテキストを継承します。await fiber.dispose() で再帰的にアンロードします。
ファイバー状態
PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED
↘ FAILED
PENDING — サービス依存関係が不足。FAILED — apply が例外をスローしたか、設定の検証に失敗。実行時にサービスが消失すると、依存するプラグインは自動的に破棄されます。
ツール
import { defineTool } from '@deepseek-ai/dsh-tools'
export const inject = ['tools']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'greet', description: '...',
parameters: { name: { type: 'string', required: true } },
output: { schema: { type: 'string' }, render: (_args, value) => [{ type: 'text', text: value }] },
async execute(args) { return `Hello, ${args.name}!` },
}))
}
defineTool はパラメータを JSON Schema に変換し、引数を検証し、アンロード時に自動登録解除します。詳細は references/basic/tool.md を参照してください。
設定
import Schema from '@deepseek-ai/schemastery'
export interface Config { greeting: string; maxRetries: number }
export const Config: Schema<Config> = Schema.object({
greeting: Schema.string().default('Hello'),
maxRetries: Schema.number().default(3),
})
export function apply(ctx: Context, config: Config) { /* 検証済み設定 */ }
interface Config と const Config: Schema<Config> の両方をエクスポートする必要があります。設定が無効な場合 → 明確なエラーとともに FAILED 状態になります。YAML で動的な値を使用するには !!js を使います: config: { apiKey: !!js process.env.API_KEY }。詳細は references/basic/config.md を参照してください。
サービス
提供: class extends Service { constructor(ctx) { super(ctx, 'name') } }
declare module '@deepseek-ai/cordis' { interface Context { name: NameService } }
消費: export const inject = ['name'] → ctx.name.method()。
オプション: ctx.get('name') → 存在しない場合は undefined を返します。
サービスの分離: group: true + isolate: { shell: true } により、各グループに独自のプロバイダーインスタンスが与えられます。詳細は references/framework/service.md を参照してください。
イベント
| モード | 呼び出し | 用途 |
|---|---|---|
emit | ctx.emit(n, ...args) | 同期的ブロードキャスト、戻り値を無視 |
parallel | await ctx.parallel(n, ...args) | 並行リスナー |
serial | await ctx.serial(n, ...args) | 逐次、最初の非 null が優先 |
bail | ctx.bail(n, ...args) | 同期的シリアル |
waterfall | ctx.waterfall(n, ...args, next) | ミドルウェアチェーン |
Waterfall リスナーは、意図的にショートサーキットしない限り 必ず next() を呼び出す必要があります。主要なハーネスイベント: agent/step、tools/result、session/event。詳細は references/framework/events.md を参照してください。
LLM アダプター
class MyAdapter extends LlmAdapter {
async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
// 変換 → プロバイダーAPI → StreamChunk を yield
}
}
ctx.llm.registerAdapter(['my-provider'], adapter)
ブロックごとの StreamChunk 順序: block-start → text-delta / tool-call-delta → block-end → usage → finish。安定したコードで LlmError をスローします。詳細は references/practice/llm-adapter.md を参照してください。
3層能力設計
定義 (Service 抽象クラス) → プロバイダー (実装) → コンシューマー (ツール)
3つすべてが inject を介して同じサービス名を共有します。各層が独立した進化を必要とする場合にのみ、別々のパッケージに分割します。詳細は references/practice/index.md を参照してください。
cordis.yml / バンドル
ローカル開発: --patch ./cordis.patch.yml
- insert:
- id: my-plugin
name: '/absolute/path/to/src/my-plugin.ts'
config: { greeting: 'Hi' }
配布: dsh.bundle マニフェスト + cordis.patch.yml を含む npm パッケージ。インストール: dsh plugin --profile demo add ./hello-plugin。
層の順序: プロファイルバンドル → プロファイルパッチ → ホームパッチ → --patch オーバーレイ。後方の層が行単位で優先されます(深いマージは行われません)。
詳細は references/basic/publish.md を参照してください。
HMR
@deepseek-ai/cordis-plugin-hmr + @deepseek-ai/cordis-plugin-logger-console + @deepseek-ai/cordis-plugin-timer をロードすると、ファイル保存時に自動リロードが行われます。
PENDING の診断
import { FiberState, type Context } from '@deepseek-ai/cordis'
for (const fiber of ctx.registry.values().flatMap(r => r.fibers))
if (fiber.state === FiberState.PENDING)
console.log(`${fiber.name} is PENDING`)
リファレンスドキュメント
references/ ディレクトリ内の詳細ガイド:
| パス | カバー内容 |
|---|---|
references/basic/ | 最初のプラグイン、ツール、設定、公開 |
references/framework/ | ライフサイクル、サービス、イベント |
references/practice/ | 3層設計、LLM アダプター |
references/cordis-tutorial/ | Cordis フレームワークのステップバイステップチュートリアル |