3.7 KiB
3.7 KiB
永続化設計
概要
llm-worker-persistence クレートは、llm-worker の Worker セッション状態を
JSONL append-only ログとして永続化する。ログを replay することで Worker 状態を完全に復元する。
設計方針
- JSONL append-only ログ: 1セッション = 1つの
.jsonlファイル。書き込みは末尾追記のみ。 - Pause/正常終了で構造に差異なし: Worker の状態は Pause 時も正常終了時も同じ形
(
history: Vec<Item>+turn_count+request_config)。resume()は「ユーザー入力を追加せずrun_turn_loop()に再入する」だけなので、 復元に必要なのは history の中身であり、前回の終了理由ではない。RunOutcomeのFinished/Paused区分は監査用メタデータであり、replay の分岐には使わない。 - クレート分離:
llm-workerは永続化を知らない。Sessionラッパーが外から Worker を包む。
命名規約
| 名前 | 用途 |
|---|---|
| SessionLog / LogEntry | 状態復元用の構造化された記録(永続化の本体) |
| EventTrace / TraceEntry | デバッグ用の生ストリームイベント全録(オプション、デフォルト OFF) |
クレート構成
llm-worker-persistence → llm-worker → llm-worker-macros
llm-worker-persistence は llm-worker に依存するが、逆方向の依存はない。
ファイル配置
{root}/{session_id}.jsonl -- セッションログ
{root}/{session_id}.trace.jsonl -- イベントトレース(デバッグ時のみ)
SessionId は UUID v7(uuid クレート)。タイムスタンプ埋め込みで辞書順 = 時系列順。
LogEntry
各エントリは Worker の特定の状態変更に対応する:
| エントリ | Worker 上の対応箇所 | replay での効果 |
|---|---|---|
SessionStart |
セッション開始 / fork | system_prompt, config, history を初期化 |
UserInput |
worker.rs:229 |
history に追加 |
AssistantItems |
worker.rs:1040-1041 |
history に追加 |
ToolResults |
worker.rs:897-900, 1072-1076 |
history に追加 |
HookInjectedItems |
worker.rs:1055 |
history に追加 |
TurnEnd |
worker.rs:1033 |
turn_count を更新 |
CacheLocked |
Worker::lock() |
locked_prefix_len を設定 |
CacheUnlocked |
Worker::unlock() |
locked_prefix_len を 0 に |
RunOutcome |
run() / resume() 終了時 |
interrupted フラグのみ(監査用) |
ConfigChanged |
set_* メソッド群 |
config を更新 |
Session ラッパー
pub struct Session<C: LlmClient, St: Store> {
pub worker: Worker<C, Mutable>,
store: St,
session_id: SessionId,
}
Session::new()— SessionStart を書き込みSession::run()— Worker::run() の前後で history を比較、差分をログ記録Session::resume()— 同上Session::restore()— ログを replay して Worker を再構築Session::fork()— 現在の history をシードにした新セッションを作成Session::fork_at()— 任意のログ地点から分岐
Store trait
pub trait Store: Send + Sync {
fn append(&self, id: SessionId, entry: &LogEntry) -> impl Future<...> + Send;
fn read_all(&self, id: SessionId) -> impl Future<...> + Send;
fn list_sessions(&self) -> impl Future<...> + Send;
fn create_session(&self, id: SessionId, entries: &[LogEntry]) -> impl Future<...> + Send;
fn exists(&self, id: SessionId) -> impl Future<...> + Send;
fn append_trace(&self, id: SessionId, entry: &TraceEntry) -> impl Future<...> + Send;
}
初期実装は FsStore(ファイルシステム JSONL)。RPITIT 使用、async_trait 不要。