4.5 KiB
llm-worker: history append を callback 経由の単一経路に閉じる
背景
pod-interrupt-prep-internalize レビュー過程で、Worker の history append API に callback を踏む経路 と 踏まない経路 が併存していることが顕在化した。
- callback を踏む経路(worker 内部 private):
extend_history_with_callbacks—emit_history_append(&item)を呼んでからself.history.push(item)。Worker::run内部の streaming commit / tool result commit はこの経路。 - callback を踏まない経路(外部公開):
Worker::push_item/Worker::extend_history/ builder のwith_items—self.history.push/extendするだけでemit_history_appendを呼ばない。
session-log への永続化は Pod::wire_history_persistence が Worker::on_history_append を立て、callback 内で classify_history_item → LogEntry::AssistantItem / LogEntry::ToolResult として writer.append_entry する作りになっている。
結果として「callback 不発火経路で append すると in-memory worker.history には載るが session-log の独立エントリにはならない」という非対称が API 契約として残っている。実際 production では Pod::apply_interrupt_prep (crates/pod/src/pod.rs:1438 / :1441) がこの不発火経路を踏んでおり、Paused→Run 時の orphan tool_result closure と interrupt system note が session-log に独立行として残らない。
CLAUDE.md の「LLM コンテキスト加工原則」は「新しい input を context に乗せたいなら、必ず先に worker.history に append して commit すること。history.json への永続化はそこから自動的についてくる」と謳っているが、この「自動的についてくる」が現状の API 契約では保証されていない。契約として callback バイパスが可能な設計であってはならない。
要件
Workerの history を成長させる経路を、必ずon_history_appendcallback を踏む単一経路に統一する。- 外部から呼び出せる「callback 不発火な history append」API を廃止する。
- 対象:
Worker::push_item、Worker::extend_history、WorkerBuilder::with_items系 - 内部実装の
extend_history_with_callbacks相当を唯一の append プリミティブに格上げする(命名は実装時に整理)
- 対象:
Pod::apply_interrupt_prepを新 API に乗せ替える。乗せ替えの副作用として、Paused→Run 時の orphan tool_result closure / interrupt system note がLogEntry::ToolResult/LogEntry::SystemItem系として session-log に独立エントリで記録されるようになる(これは本チケットで肯定的に取り込む変化)。- 注: system message は
PodInterceptor経由でLogEntry::SystemItemとして典型化されている経路があるので、callback 内のフィルタ (pod.rs:381-389のRole::Systemskip) との重複を作らないこと。interrupt system note は callback 単独で書く / interceptor 単独で書く / 両方書かない、のいずれかに整合させる。実装時に確認。
- 注: system message は
worker_state_test.rsを含む既存テストは、新 API に書き換えるか、builder 段階で history を仕込む正当な用途として整理する。前者を基本とする。
スコープ外
Worker::clear_historyの扱い(append ではなく削除なので別論点)。LogEntryバリアントの設計変更。- callback で書かれるエントリの形式・命名の整理(
classify_history_itemの現行挙動を前提として進める)。 Notify/PodEvent/<system-reminder>系の history 反映ポリシー全体(system-reminder注入機構の汎用化として別途整理する。本チケットはあくまで「API 契約から callback バイパスを消す」レイヤに閉じる)。
完了条件
Worker::push_item/Worker::extend_history/WorkerBuilder::with_items等、callback を踏まずにworker.historyを成長させられる public API がコードベースに存在しない。cargo check --workspaceとcargo test -p llm-worker --lib/cargo test -p podが通る。apply_interrupt_prepが新 API 経由になり、interrupt 前処理由来の append が session-log の独立エントリとして残ることを~/.insomnia/sessions/*.jsonlで目視確認できる(手順をレビュー時の備考に記載)。