Skip to content

ストレージ

Triggerfishのすべてのステートフルデータは統一されたStorageProvider抽象化を通じて 流れます。どのモジュールも独自のストレージメカニズムを作成しません — 永続化が必要な すべてのコンポーネントは依存関係としてStorageProviderを受け取ります。この設計に より、ビジネスロジックに触れることなくバックエンドを交換でき、すべてのテストを 高速で決定論的に保てます。

StorageProviderインターフェース

typescript
interface StorageProvider {
  /** キーで値を取得。見つからない場合はnullを返す。 */
  get(key: string): Promise<StorageValue | null>;

  /** キーに値を保存。既存の値は上書き。 */
  set(key: string, value: StorageValue): Promise<void>;

  /** キーを削除。キーが存在しない場合はno-op。 */
  delete(key: string): Promise<void>;

  /** オプションのプレフィックスに一致するすべてのキーをリスト。 */
  list(prefix?: string): Promise<string[]>;

  /** すべてのキーを削除。注意して使用。 */
  clear(): Promise<void>;
}

StorageValueは文字列です。すべての構造化データ(セッション、系譜レコード、

設定)はストレージ前にJSONにシリアライズされ、読み取り時にデシリアライズされます。 これによりインターフェースがシンプルでバックエンドに依存しない状態を保ちます。 :::

実装

バックエンドユースケース永続性設定
MemoryStorageProviderテスト、エフェメラルセッションなし(再起動で失われる)設定不要
SqliteStorageProvider個人ティアのデフォルト~/.triggerfish/data/triggerfish.dbのSQLite WALゼロ設定
エンタープライズバックエンドエンタープライズティア顧客管理Postgres、S3、またはその他のバックエンド

MemoryStorageProvider

速度と決定論のためにすべてのテストで使用されます。データはメモリにのみ存在し、 プロセスが終了すると失われます。すべてのテストスイートは新鮮な MemoryStorageProviderを作成し、テストが分離されて再現可能であることを保証します。

SqliteStorageProvider

個人ティアデプロイメントのデフォルト。同時読み取りアクセスとクラッシュセーフのために SQLiteをWAL(Write-Ahead Logging)モードで使用します。データベースは以下に置かれます:

~/.triggerfish/data/triggerfish.db

SQLiteは設定不要、サーバープロセス不要、ネットワーク不要です。単一のファイルが すべてのTriggerfishの状態を保存します。@db/sqlite DenoパッケージがバインディングTo 提供し、--allow-ffi権限が必要です。

SQLite WALモードは単一のライターで複数のリーダーがデータベースに同時アクセス

できます。これはGatewayにとって重要で、エージェントがツール結果を書き込んでいる間も セッション状態を読み取れます。 :::

エンタープライズバックエンド

エンタープライズデプロイメントはコード変更なしに外部ストレージバックエンド(Postgres、 S3など)をプラグインできます。StorageProviderインターフェースの任意の実装が機能します。 バックエンドはtriggerfish.yamlで設定されます。

名前空間付きキー

ストレージシステムのすべてのキーはデータタイプを識別するプレフィックスで名前空間 付けされています。これにより衝突を防ぎ、カテゴリーでデータをクエリ、保持、削除 することが可能になります。

名前空間キーパターン説明
sessions:sessions:sess_abc123セッション状態(会話履歴、メタデータ)
taint:taint:sess_abc123セッションtaintレベル
lineage:lineage:lin_789xyzデータ系譜レコード(プロベナンス追跡)
audit:audit:2025-01-29T10:23:45Z:hook_pre_output監査ログエントリ
cron:cron:job_daily_reportCronジョブの状態と実行履歴
notifications:notifications:notif_456通知キュー
exec:exec:run_789エージェント実行環境の履歴
skills:skills:skill_weatherインストール済みSkillのメタデータ
config:config:v3設定スナップショット

保持ポリシー

各名前空間にはデフォルトの保持ポリシーがあります。エンタープライズデプロイメントは これらをカスタマイズできます。

名前空間デフォルト保持期間理由
sessions:30日会話履歴は期限切れになる
taint:セッション保持に一致taintはセッションなしでは意味がない
lineage:90日コンプライアンス主導、監査証跡
audit:1年コンプライアンス主導、法律・規制対応
cron:30日デバッグ用の実行履歴
notifications:配信後 + 7日未配信の通知は永続化する必要がある
exec:30日デバッグ用の実行アーティファクト
skills:永続インストール済みSkillメタデータは期限切れにならない
config:10バージョンロールバック用のローリング設定履歴

設計原則

すべてのモジュールがStorageProviderを使用

Triggerfishのどのモジュールも独自のストレージメカニズムを作成しません。セッション 管理、taint追跡、系譜記録、監査ログ、cronの状態、通知キュー、実行履歴、設定 — すべてがStorageProviderを通じて流れます。

これが意味すること:

  • バックエンドの交換には依存性注入ポイントを1つ変更するだけ
  • テストは速度のためにMemoryStorageProviderを使用 — SQLiteのセットアップ不要、 ファイルシステム不要
  • 保存時の暗号化、バックアップ、またはレプリケーションを実装する場所が正確に1つある

シリアライゼーション

すべての構造化データはストレージ前にJSON文字列にシリアライズされます。 シリアライズ/デシリアライズレイヤーは以下を処理します:

  • Dateオブジェクト(toISOString()でISO 8601文字列にシリアライズ、new Date()で デシリアライズ)
  • ブランデッド型(基礎となる文字列値としてシリアライズ)
  • ネストされたオブジェクトと配列
typescript
// セッションを保存
const session = {
  id: "sess_abc",
  taint: "CONFIDENTIAL",
  createdAt: new Date(),
};
await storage.set("sessions:sess_abc", JSON.stringify(session));

// セッションを取得
const raw = await storage.get("sessions:sess_abc");
if (raw) {
  const session = JSON.parse(raw);
  session.createdAt = new Date(session.createdAt); // Dateを復元
}

イミュータビリティ

セッション操作はイミュータブルです。セッションを読み取り、変更し、書き戻すと 常に新しいオブジェクトが生成されます。関数は格納されたオブジェクトをインプレースで 変更しません。これはTriggerfishの広いggg原則、つまり関数は新しいオブジェクトを返し、 変更しないというものと一致します。

ディレクトリ構造

~/.triggerfish/
  config/          # エージェント設定、SPINE.md、TRIGGER.md
  data/            # triggerfish.db(SQLite)
  workspace/       # エージェントexec環境
    <agent-id>/    # エージェントごとのワークスペース(永続)
    background/    # バックグラウンドセッションのワークスペース
  skills/          # インストール済みSkill
  logs/            # 監査ログ
  secrets/         # 暗号化された認証情報ストア

セキュリティ secrets/ディレクトリにはOSキーチェーン統合によって管理

される暗号化された認証情報が含まれています。設定ファイルやStorageProviderに シークレットを保存しないでください。OSキーチェーン(個人ティア)またはvault統合 (エンタープライズティア)を使用してください。 :::