バグ #135
完了summarize を CLI LLM バックエンドに切り替え + 構造化スナップショット対応
0%
説明
h2. 背景
現在の session_log summarize は Gemini API (Python SDK) を直接叩いている(gemini_client.py)。
しかし以下の問題が判明した:
- API 経由はトークン課金が発生し、プロジェクト文脈を毎回渡すとコスト増
- AI による「要約」は重要度判断ができず、セッション引き継ぎに不十分(#128, 前セッションで合意)
- Gemini CLI / Codex CLI(サブスク定額)で同等以上の品質が得られることを実験で確認済み
h2. 方針
h3. 1. core 層: LLM CLI バックエンド追加
既存の Ollama バックエンド(qwen_gate.py / agent_backend.py)と並ぶ形で、CLI 経由の外部 LLM 呼び出し基盤を追加する。
- Gemini CLI: Windows ネイティブ。パイプで stdin → stdout。デフォルト
- Codex CLI: WSL 経由。nvm source が必要。エージェントモードで動く
- エンジン切り替え可能な共通インターフェース
h3. 2. session_log: summarize 改修
- gemini_client.py(API 直叩き)を廃止
- 新しい CLI バックエンドを利用する形に切り替え
- 出力形式を「自由形式の要約」から「構造化スナップショット」(固定スロットの穴埋め)に変更
- プロジェクト文脈(マスタードキュメント等)を自動付与して品質向上
- デフォルトエンジン: gemini-cli
h3. 3. 構造化スナップショットのスロット
| スロット | 内容 |
|---|---|
| CURRENT_STATE | セッション終了時点のシステム・機能の状態 |
| DISCOVERY | 新たに判明した技術的事実や合意事項 |
| DECISION | 明示的に決定されたこと |
| NEXT_ACTION | 次セッションで着手すべき具体的アクション |
| BLOCKED / PENDING | 未解決の問題、保留事項 |
| RISKS | 注意すべきリスクや制約 |
h2. ドキュメント更新
- docs/capabilities/session_log/要約転記仕様書.md → v0.2 に更新(CLI バックエンド利用、構造化スナップショット)
- docs/reference/01_アーキテクチャ定義書.md → CLI LLM バックエンドの追記
h2. 実験結果(根拠)
同一の生ログ(529行, 40KB)に対して3パターンで実験:
| 条件 | 品質 | コスト | 実行時間 |
|---|---|---|---|
| Gemini CLI + ログのみ | 良 | 定額 | 数秒 |
| Gemini CLI + ログ + マスタードキュメント | 最良 | 定額 | 数秒 |
| Codex CLI + ログのみ(WSL) | 非常に高い | 定額 | 長い(エージェントモード) |
文脈を渡すと設計判断の抽出精度が明らかに向上した。
LLM AI さんが26日前に更新
h3. CLI LLM 実験スクリプトの記録
実験で使用した @tmp_codex_test.sh@ を一度コミットして履歴に残し、その後削除する。
このスクリプトは Codex CLI (WSL経由) の動作検証に使用したもの:
- WSL 上の nvm 経由で Codex CLI を呼び出す方法の確立
- @ChatGPT codex exec@ の非対話モードでの構造化スナップショット生成テスト
実験結果は本チケットの description に記載済み。スクリプト自体は実験完了後に削除する。
LLM AI さんが26日前に更新
h3. 実装前の設計判断 3点
h4. 1. source_file 未指定時の挙動
現行の「その場で save してから使う」を維持する。
session_logs/ の最新 .txt を使う方式だと、今回のセッション分が欠ける可能性がある。
source_file 指定時のみ明示ファイルを使う。要約転記仕様書 v0.2 の記述を実装に合わせて修正すること。
h4. 2. codex-cli は WSL 専用
WSL 専用とする。Windows 側へのフォールバックは不要。
理由: あきらさんが「Windows に直接載せるのはまだベータで WSL で動かせと言われた」と報告済み。
Windows 側に codex.exe があってもそれは別物なので、混在を避ける。
h4. 3. STARTUP_CONTEXT.md は最小テンプレートで上書き
毎回固定テンプレートに上書きする(スナップショットへのリンク + 一言まとめ)。
現状の補助資料表や注意書きを含む構造は維持しない。
理由: STARTUP_CONTEXT.md は「Butler だけが更新する」ルール(#128 で合意済み)なので、機械的に生成しやすい最小形が適切。必要なら人間が手で補足する。
LLM AI さんが26日前に更新
#135 対応を実装し、以下のコミットを作成しました。
commit: 21ce6bdf344381c451a7bb536623348e29db56e9
message: feat: switch session_log summarize to CLI LLM refs #135
実装内容:
-
butler/llm_cli.pyを追加し、gemini-cli/codex-cliを呼ぶ CLI LLM バックエンドを実装 -
session_log summarizeを Gemini API 直叩きから CLI バックエンド利用へ切り替え -
source_file未指定時は、現行方針どおり現在セッションを save してから summarize する挙動を維持 -
codex-cliは WSL 経由のみとし、Windows 側codex.exeにはフォールバックしない - 出力を
_snapshot.mdに変更し、STARTUP_CONTEXT.mdは最小テンプレート(最新スナップショットへのリンク + 一言まとめ)で更新 - 旧
gemini_client.pyを削除 -
skills_registry/要約転記仕様書/session_logテストを更新
確認結果:
-
python -m pytest tests/test_session_log_handler.py -q→ 7 passed -
python -m pytest tests/test_main_submit_sync.py::test_session_log_submit_task_is_synchronous -q→ 1 passed -
python -m pytest -qは実行済みですが、今回変更と無関係な既存失敗が 4 件ありましたtests/test_phase2_trilium_e2e.py::test_phase2_trilium_e2etests/test_wiki_handler.py::test_add_project_successtests/test_wiki_handler.py::test_add_project_deniedtests/test_wiki_handler.py::test_sync_success
LLM AI さんが26日前に更新
h3. 実装レビュー結果
コミット @21ce6bd@ の実装をレビューした。結果: 合格。
h4. 変更ファイル(6ファイル、+481/-143)
| ファイル | 変更内容 |
|---|---|
| @butler/llm_cli.py@ | 新規。core 層の CLI LLM バックエンド。gemini-cli / codex-cli の共通インターフェース |
| @butler/capabilities/session_log/handler.py@ | summarize を CLI バックエンドに切り替え。構造化スナップショット対応 |
| @butler/capabilities/session_log/gemini_client.py@ | 削除(API 直叩き廃止) |
| @butler/skills_registry.py@ | summarize の engine パラメータ追加 |
| @docs/capabilities/session_log/要約転記仕様書.md@ | 設計判断の反映(source_file、codex-cli WSL専用、STARTUP_CONTEXT最小テンプレート) |
| @tests/test_session_log_handler.py@ | 新規テスト2件追加(明示ファイル / 現在セッションsave後使用) |
h4. 設計判断との整合性
3点とも正しく反映されている:
source_file 未指定時は現在セッションを save してから使う(維持) ✔¶
codex-cli は WSL 専用(@wsl.exe bash -lc@ で呼び出し、フォールバックなし) ✔¶
STARTUP_CONTEXT.md は最小テンプレートで上書き(@_build_startup_context@ 関数) ✔¶
h4. コード品質
- @llm_cli.py@ の構造が良い。@run_prompt()@ を公開インターフェースにし、エンジン切り替えは内部に閉じている
- Codex CLI の WSL 呼び出しで nvm source が必要な問題を @_build_codex_wsl_script@ で対応済み
- @_strip_outer_code_fence@ で LLM が余計なコードフェンスを付けた場合の対策もある
- @_extract_first_meaningful_line@ で STARTUP_CONTEXT の「一言まとめ」を CURRENT_STATE から自動抽出
- 環境変数 @BUTLER_GEMINI_CLI_MODEL@ / @BUTLER_CODEX_CLI_MODEL@ でモデルを外部から切り替え可能
h4. テスト
7件全パス(既存5件 + 新規2件)。run_prompt を monkeypatch で差し替えており、ユニットテストとして適切。
h4. 残作業
- CLI 実接続の E2E テスト(Gemini CLI が実際に動く環境での確認)
- Codex CLI 側の E2E 確認(WSL 上で実際に動作するか)
LLM AI さんが26日前に更新
h3. CLI 実接続 E2E の実施と追補修正
実接続 E2E を実施し、環境差分を吸収するための追補修正をコミットした。
commit: 20f0b04258362a0c3f53aa4ab5f1b2c4d35f9ee2
message: fix: harden CLI LLM runner for real E2E refs #135
h4. 追補修正の内容
対象: @butler/llm_cli.py@
- Windows 側で @gemini@ が @subprocess.run()@ から見つからない環境に対応し、@gemini.cmd@ を優先解決するよう変更
- Gemini CLI の出力で CP932 デコード例外が出たため、subprocess の文字コードを UTF-8 + replace に固定
- WSL 経由の @bash -lc@ に渡すスクリプトで、@$HOME@ / @$PATH@ / @$candidate@ などの変数がホスト側で潰れないようエスケープを修正
- WSL 内の @~/.nvm/versions/node/*/bin/codex@ を探索し、@codex@ を PATH へ明示追加するよう変更
- Codex CLI が見つからない場合のエラーメッセージを明確化
h4. E2E 結果
いずれも @session_log summarize@ の実経路で確認した。
一時ワークスペースを作成し、@source_file@ と @docs/マスタードキュメント.md@ を置いた状態で Butler handler を実行。
確認対象は以下:
- CLI 実行が成功すること
- @_snapshot.md@ が生成されること
- @STARTUP_CONTEXT.md@ が更新されること
h5. 1. Gemini CLI 実接続 E2E
- status: ok
- elapsed: 約 51.3 秒
- 生成物:
** @claude_code_test_20260321T030000Z_snapshot.md@
** @STARTUP_CONTEXT.md@ - 確認事項:
** 構造化スナップショット生成成功
** STARTUP_CONTEXT の最小テンプレート更新成功
h5. 2. Codex CLI 実接続 E2E (WSL)
- status: ok
- elapsed: 約 12.44 秒
- 生成物:
** @claude_code_test_20260321T031000Z_snapshot.md@
** @STARTUP_CONTEXT.md@ - 確認事項:
** WSL 経由で @ChatGPT codex exec@ が成功
** 構造化スナップショット生成成功
** STARTUP_CONTEXT の最小テンプレート更新成功
h4. 補足
E2E 実施後に @python -m pytest tests/test_session_log_handler.py -q@ を再実行し、7件 pass を確認した。
今回の追補修正は実環境差分の吸収が主で、既存 unit test は維持できている。
LLM AI さんが26日前に更新
h3. Brain 側からの Butler 実接続 E2E 確認
Codex が実施した E2E テスト(コメント #339)の後、Brain 側から実際に Butler 経由で @summarize@ を実行して確認した。
h4. 実行条件
- Butler reload 後に実行
- @source_file@: @session_logs/claude_code_9afce4ef-..._20260320T134357Z.txt@(前セッションの生ログ)
- @engine@: @gemini-cli@
- Butler 経由(@butler__submit_task@ → handler → @llm_cli.run_prompt@ → Gemini CLI)
h4. 結果: 成功
- status: ok
- 生成物:
** @session_logs/claude_code_9afce4ef-..._20260320T134357Z_snapshot.md@ — 構造化スナップショット(6スロット全て埋まっている)
** @STARTUP_CONTEXT.md@ — 最小テンプレートで上書き更新済み
h4. 品質確認
スナップショットの内容を確認:
- CURRENT_STATE: summarize 機能の実装完了状態を正確に記述
- DISCOVERY: AIの自律的記録の限界、チケット紐付けの不適切さなど、設計上の重要な発見を抽出
- DECISION: 「機械的な引き継ぎフロー」「STARTUP_CONTEXT は Butler のみ更新」などの判断を正確に記録
- NEXT_ACTION: 具体的な次ステップが列挙されている
- RISKS: 「Gemini は会話内の言及のみ」「STARTUP_CONTEXT 競合」など適切
STARTUP_CONTEXT.md も「リンク + 一言まとめ」の最小テンプレートで正しく更新されている。
h4. 結論
実装は仕様通りに動作しており、#135 の主要作業は完了と判断する。
残るのは @google-generativeai@ パッケージの依存削除(gemini_client.py 廃止に伴う)程度。