12 KiB
Pod Factory: 設定カスケードとプロンプト資産による Pod 自動生成
背景
現状、Pod を起動するには test_pod.local.toml のような完全な PodManifest TOML を手書きする必要がある。1 人のユーザーが1 つのエージェントを試験運用するには十分だが、Insomnia が狙う「複数のエージェントが独立プロセスとして spawn されて自律的に動く」世界観では、Pod のライフサイクル全体が自動化可能でなければならない。そのためには、Pod の作成自体も自動化可能である必要がある。
手書きマニフェストには以下の問題がある:
- 1 Pod = 1 ファイルで、Pod を動的に増やす用途にスケールしない
- 設定項目が多く(
worker.*/provider.*/scope.*/compaction.*/tool_output.*等)、毎回コピペしてわずかな差分だけ書き換える苦行になる - system_prompt を TOML 文字列に埋め込む形はプロンプト資産の再利用性が低い
- Pod の起動条件の共通部分(プロバイダ・モデル・デフォルトツール設定など)は本来一度書けば良いのに、毎回書かされる
ゴール
Pod 作成を「最終的に PodManifest を1 つ構築する問題」として定式化し、その PodManifest をカスケード + 差分上書きで組み立てる基盤を提供する。手書きが必要な TOML は「ユーザー / プロジェクト単位のデフォルト上書き」だけに縮退させ、個別の Pod 起動ごとに人間が TOML を触らない状態を目指す。
プロンプトは手書きマニフェストに文字列を埋め込む方式をやめ、テンプレート資産ライブラリとして参照可能にする。
方針
同じ型で、層で上書きする
- 解決後の型は現行の
manifest::PodManifestのまま。Pod 側の契約(Pod::from_manifest)は変更しない。 - カスケードは
PodManifestより上の「部分的なPodManifestを層ごとに保持し、順番にマージして最終形を作る」層として設計する。 - 各層は部分形を持てる(全フィールドを埋める必要はない)。存在するフィールドだけが下層を上書きする。
カスケードの層
優先順位が低い方から高い方へ:
- ビルトインのデフォルト: コードに焼き込んだ基本値(現在
PodManifest各フィールドの#[serde(default)]やDefault実装に散っているものを集約) - ユーザー設定:
~/.config/insomnia/config.tomlなど。ユーザー個人のプロバイダ指定・デフォルトモデル・常用ツール設定等を書く - プロジェクト設定: プロジェクト直下の
.insomnia/config.tomlなど。プロジェクト固有の scope・compaction 設定・system_prompt のベース等を書く - プログラマティック上書き: Pod 生成を呼ぶコード(GUI / CLI / 別 Pod からの spawn 等)が渡す
PodManifestOverlay的な部分形。ここでpod.nameやpod.pwdのようなその Pod に固有の値を与える
各層とも人間が書くときは PodManifest と同じ TOML スキーマで書く(サブセット可)。
マージのセマンティクス
- スカラー (
String,u32,bool等): 上層が存在すれば丸ごと置換 - Option 型: 上層が
Someなら置換、Noneなら据え置き - マップ (例:
tool_output.per_tool): キー単位でマージ、同一キーは上層優先 - リスト (例:
scope.allow/scope.deny): 原則置換(append にすると下層の意図しないルールが漏れる危険)。ただし append したいケースはあるので、設計時に decoration の形式(例:scope.allow_extraなど)を別途検討 - 未知フィールドは manifest エラーにせずログ警告
プロンプト資産ライブラリ
- プロンプトは TOML 文字列ではなくファイルとして管理する。
- 検索パスはカスケードと対応した3層:
- ビルトイン: バイナリに同梱されたデフォルトプロンプト(
coder/reviewer/planner等、設計時に選定) - ユーザー:
~/.config/insomnia/prompts/*.md等 - プロジェクト:
.insomnia/prompts/*.md等
- ビルトイン: バイナリに同梱されたデフォルトプロンプト(
- 同名があれば上層が優先。
- 既存の
SystemPromptTemplate(minijinja ベース)のローダを拡張し、テンプレート内から他のプロンプトを{% include "coder" %}/{% import "planner" as p %}のように参照できるようにする。 - 層の異なる同名プロンプトを合成するための include 先解決は上記優先順位に従う。
設定値のテンプレート参照は扱わない
worker.max_tokens = "{{ env.INSOMNIA_MAX_TOKENS }}" のような設定値の中でテンプレートを展開する機能は本チケットの範囲外とする。テンプレートエンジンはプロンプト本文の組み立てだけに限定する。設定値の動的化が必要になった時点で別チケットで検討する。
プログラマティック Pod 作成 API
-
Pod::from_manifest(path)の隣に、カスケード解決を経由する生成経路を追加する。イメージ:// 層を明示的に指定して最終形を得る let manifest = PodFactory::new() .with_user_config(user_config_path)? // absent OK .with_project_config(project_root)? // absent OK .with_overlay(overlay_toml_or_struct) // programmatic .resolve()?; // -> PodManifest Pod::from_manifest(manifest, store).await?; -
細かい形状は設計時に詰める(builder 型 vs 関数型、
overlayを TOML 文字列か型付きか等)。 -
CLI からは
insomnia spawn --overlay '...'相当で同じ経路を叩く想定。
要件
カスケード基盤
- ユーザー設定・プロジェクト設定・プログラマティック overlay を順に重ねた結果が
PodManifestとして取れる。 - 各層が部分形を許容する(
pod.pwdだけ書いてあっても良い等)。 - マージセマンティクスがフィールドごとに定義され、テストされる(スカラー / Option / マップ / リスト)。
- 層が全て空でもビルトインデフォルト単体で有効な manifest にならない(少なくとも
pod.pwdとproviderとscope.allowは上位層で与える必要がある)。その旨を resolve 時のエラーで明示する。
プロンプト資産ライブラリ
- 3層の検索パスでプロンプトファイルを解決できる。
- 同名プロンプトは上層優先で解決される。
SystemPromptTemplateの minijinjaEnvironmentにカスタムローダを仕込み、{% include "name" %}/{% import "name" as x %}で資産を参照できる。- プロンプト資産自体もテンプレートとして評価され、現行の
SystemPromptContext(now/cwd/scope/tools/files等)と同じ変数が見える。
プログラマティック Pod 作成
- 既存の
Pod::from_manifestを壊さず、追加経路としてPodFactory系の API を提供する。 - TUI / GUI / daemon 等の上位クライアントが、TOML ファイルパスではなくオーバーレイ + 設定ディレクトリパスを渡すだけで Pod を起動できる。
ドキュメント
- カスケード層の優先順位・マージ規則を
docs/にまとめる。 - ユーザー設定 / プロジェクト設定ファイルの最小例と全オプション例を残す。
設計で決めること
- ユーザー設定のパス:
~/.config/insomnia/config.tomlか、XDG 非準拠のパスも許容するか。環境変数で上書きできるか。 - プロジェクト設定の場所: プロジェクトルートの
.insomnia/config.tomlか、別の命名か。サブディレクトリから起動したときの discovery(上位ディレクトリ探索)の挙動。 - プロジェクトルートの判定: 明示指定 vs
.gitや.insomnia/で自動検出 - preset の概念を入れるか: 名前付きの overlay セット(例:
insomnia spawn coder)を導入するか。導入する場合、preset はユーザー設定内に[preset.coder]として持つか、個別ファイル~/.config/insomnia/presets/coder.tomlとして持つか - リストフィールドのマージ方針: 置換 only にするか、append 用の別フィールド (
scope.allow_extra等) を用意するか - ビルトインプロンプトの初期ラインナップ: どの役割をデフォルトで同梱するか、どこに置くか(
crates/pod/assets/prompts/*.mdをinclude_str!で埋め込む等) - プロンプト資産のファイル形式:
.mdか.txtか、拡張子省略可能にするか、フロントマター(YAML/TOML)で引数デフォルトを持たせるか - プロンプト include 時の context 伝搬: 親テンプレートの変数を include 先でも見えるようにするか、明示的に
withで渡させるか - エラー戦略: 上層で書かれた未知フィールドや型ミスマッチをどこまで寛容に扱うか
- 既存の
Pod::from_manifest(path)とのインターフェース整理: 廃止するか、内部的に PodFactory に委譲するか - CLI コマンド名:
insomnia spawn/insomnia pod new/ その他
完了条件
PodManifestの最終形を層のマージで構築するPodFactory(または同等の仕組み)が実装され、マージセマンティクスの単体テストが通る。- ユーザー設定・プロジェクト設定・プログラマティック overlay のすべての層を使う end-to-end テストで、Pod が TOML ファイルパスを一切渡さずに起動できる。
- プロンプト資産ライブラリを経由して system_prompt が組み立てられ、
{% include "ビルトイン名" %}で同梱プロンプトを参照できることをテストで確認できる。 - ユーザー設定ファイル / プロジェクト設定ファイルのドキュメントが
docs/に存在する。 - 既存の
Pod::from_manifest(path)経路が動き続ける(回帰させない)。
他チケットとの関係
tickets/native-gui-mvp.md: 現状「manifest ファイルを選ぶ UI」を含むが、本チケット完了後はその UI が「preset 選択 + overlay 入力」に置き換わる想定。native-gui-mvp 実装時に本チケットの API を使うか、先に文字列パス渡しで済ませて後から差し替えるかは別途判断tickets/tui-pod-spawn-ui.md: 同上。Pod spawn UI は本チケットが提供する API の上に構築されるtickets/protocol-design.md: Pod ↔ Client protocol 自体は変わらない。spawn 要求を protocol に載せるかどうかは protocol-design 側で検討docs/system-prompt-template.md/crates/pod/src/system_prompt.rs: プロンプト資産ライブラリはこの minijinja 基盤の拡張として実装される
範囲外
- 設定値の中のテンプレート展開(
max_tokens = "{{ env.X }}"のような動的値)。プロンプト本文のテンプレート展開のみを扱う - GUI 内での設定ファイル編集 UI。編集は人間がエディタで TOML を書くだけ(あくまで「Pod 生成時に手書きしない」ことを目指す)
- チーム共有・同期。ユーザー設定とプロジェクト設定は各自・各リポジトリ単位で管理される
- 秘密情報管理(API キー等)。既存の
api_key_file方式を維持する - 設定値の型バリデーション強化(JSON Schema など)。現行の serde ベースで十分な範囲に留める