基盤となるカーネル、Cordis
CordisはKoishiコミュニティによるTypeScriptプラグインフレームワークです。DSHは独自のプラグインシステムを実装していません。このフレームワークを利用しているため、DSHプラグインはCordisプラグインとなっています。
Contextはサービスの集積所です
すべてのプラグインは、慣習的にctxと呼ばれるContextを受け取ります。サービスはctx.tools、ctx.llm、ctx.sessionsといった安定したキーの下で管理されます。ツールテーブルを必要とするプラグインは特定のキーを参照しますが、具体的な実装は参照しません。そのため、プラグイン側で気づくことなく、そのキーの背後にある実装を変更することが可能です。
import type { Context } from 'cordis'
// Services live on the context under stable keys.
// A plugin reaches for the key, not for a concrete class.
export function apply(ctx: Context) {
ctx.tools // the tool table
ctx.sessions // the append-only session log
ctx.llm // whichever model adapter is loaded
} Serviceを実装するものはすべてプラグインです
実際には、これはapply(ctx)の本体を持つ関数、またはCordisが現在のContextにライフサイクルをマウントするServiceを継承したクラスを意味します。それ以外に、登録マニフェストや継承すべきプラグインのベースクラスは存在しません。
ロード順序は宣言されるものであり、順序付けられるものではありません
プラグインは必要なものをinjectにリストアップします。Cordisは、リストされたすべてのサービスが存在するまでそれを保留状態に保ち、その後applyを呼び出します。起動順序を手動で管理する必要はなく、依存関係よりも先に到達したプラグインは、クラッシュする代わりに単に待機します。
export const inject = ['tools', 'sessions']
export function apply(ctx: Context) {
// Cordis holds this plugin in a pending state until both
// services exist, so neither lookup below can be undefined.
const session = ctx.sessions.current()
ctx.tools.list().forEach((tool) => session.note(tool.name))
} applyの内部では、injectで指定されたすべてのものが存在することが保証されます。
副作用は可逆的です
ctx.onやctx.effectを通じて行われた登録は追跡されます。プラグインがアンロードまたはリロードされると、Cordisはその記録をたどり、それぞれを元に戻します。リスナーは削除され、サービスは解放され、タイマーはクリアされます。これにより、プラグインのホットスワップが、緩やかなメモリリークを引き起こすことなく安全に行えるようになります。
export function apply(ctx: Context) {
const dispose = ctx.tools.register('read_file', async ({ path }) => {
return readFile(path, 'utf8')
})
// Returning the disposer is what makes the plugin removable:
// unloading it takes the tool back out of the table.
return dispose
} イベントをディスパッチする4つの方法
プラグインはサービスだけでなくイベントを通じても相互に通信し、ディスパッチモードによってリスナーが実行できることが決定されます。
emit ファイア・アンド・フォーゲット(送信後に放置)。すべてのリスナーが実行され、何も返されません。
parallel すべてのリスナーが並行して実行され、呼び出し元はそれらすべてを待ちます。
serial リスナーは順に実行され、いずれかが値を返すまで実行が続けられ、その値が結果となります。
waterfall 各リスナーはnextを受け取り、引数を変換したり、処理を委譲したり、ショートサーキット(早期終了)させたりすることができます。
これがDSHでどのように現れるか
すべてのDSH機能はContext上のサービスです。リストを読むことが、ハーネスが実際に何で構成されているかを理解する最も早い方法です。
- モデルアダプターはサービスキーを要求します。プロバイダーを切り替えるということは、同じキーに対して異なるプラグインをロードすることを意味します。
- 各ツールは可逆的なエフェクトとしてツールテーブルに自身を登録するため、ツールを削除することはそのプラグインをアンロードすることを意味します。
- セッションサービスは追記専用(append-only)のログを所有します。ストレージバックエンドは、その背後にある個別のプラグインです。
- エージェントループ自体がプラグインです。そのため、MinimalやPTCのようなプリセットは、カーネルを共有しながらも大きく異なることができます。
Cordisの背後にある構成可能性(composability)モデルは、時空間構成可能性(spatiotemporal composability)に関する論文にまとめられており、DSHのリポジトリからリンクされています。