7.6 KiB
7.6 KiB
Review: メモリ機構: memory / Knowledge 検索ツール
前提・要件の確認
ツール構成
- MemorySearch / KnowledgeSearch を新規 Tool として実装、単一取得は MemoryRead に役割分離 —
crates/memory/src/tool/search.rs、tool/mod.rs:21-24でread_tool/write_tool/edit_tool/memory_search_tool/knowledge_search_toolを re-export。チケット冒頭の「slug 完全一致は MemoryRead 側」という補正が公開 API・ドキュコメントどちらにも反映されている (search.rs:31-40,read.rs:17-20)。
Read/Write/Edit signature 補正(memory-file-format からの繰越)
MemoryToolKindをtool/mod.rs:28-90に集約し、Read/Write/Edit 全部でkind+slug入力に切り替え済み。Workflowを意図的に enum から外しているため、workflowを投げた瞬間 deserialize で弾ける(write.rs:230-243,edit.rs:240-253のテストで担保)。Search 出力{slug, kind}をそのまま Read/Edit に渡せる経路は完了条件どおり成立。- summary は
slug禁止、その他は必須、というルールをMemoryToolKind::resolve_pathに一箇所で集約しており、3 ツール全部が同じ振る舞いになる。テストもsummary_with_slug_rejected/decision_without_slug_rejectedで担保 (read.rs:172-187).
MemorySearch 仕様
- 入力
query: stringのみ、case-insensitive 部分一致 —validate_queryで空文字拒否 + lower-case 化 (search.rs:224-231)、scan_textで行ごとに lower-case 化して比較 (search.rs:289-300)。 - 出力
{slug, kind, excerpt}[]、summary は slug を"summary"固定で返す —search.rs:115-122とmemory_search_finds_summaryテスト。 - 対象/除外ディレクトリ:
summary_path/decisions_dir/requests_dirのみ列挙し、workflow_dir/staging_dirはそもそも触らない構造。memory_search_excludes_workflow_and_stagingテストで「needle を含めても 0 件」を担保。
KnowledgeSearch 仕様
query必須 +kind任意フィルタ。frontmatter が壊れていても本文 grep を継続、frontmatter フィールドはNoneを返す動作 (search.rs:182-213)。knowledge_search_searches_frontmatter_tooで frontmatter 文字列にもヒットすることを担保。- 出力スキーマ差別化(description / model_invokation を持つ)はチケット改訂版にも記述あり、原チケットの「同型」を読み手にも明示している。
共通・ソート・上限
list_md_filesがスラグ昇順ソート (search.rs:256)、ファイル内はlines().enumerate()で出現順 — チケットの「ファイル名昇順 → 行順」と一致。manifest [memory]からsearch_hit_limit/search_excerpt_linesを tune できる経路あり (crates/manifest/src/lib.rs:54-64,config.rs:204-212,controller.rs:249-260)。デフォルト 20 / 3 行で原仕様と一致。memory_search_respects_hit_limit/memory_search_excerpt_includes_context_linesテストで両方が効くことを担保。
登録
pod/src/controller.rs:256-260で memory enabled 時にのみ 5 ツールが並列登録される。Phase 2 Pod 側はチケットでも明示的に範囲外と書かれていて整合。
完了条件マッピング
- 通常 Pod から 5 ツール呼べる ✅ (
controller.rs) - Search → Read 経路成立 ✅(共通
MemoryToolKindで型一致) - frontmatter 含む全文ヒット ✅ (
scan_textは raw 全体を走査、専用テストあり) kindfilter ✅ (knowledge_search_kind_filterテスト)- 対象外ディレクトリ非ヒット ✅
- tuning 可 ✅
アーキテクチャ・スコープ
crates/memory/src/tool/にファイル分割で同居、既存 read/write/edit と完全に同じパターン。MemoryToolKindをmod.rsに置いて 4 ツール全部が共有しているのは適切。- 依存追加なし(
std::fs/serde_yaml/ 既存のschema::*のみ)。cargo addルールに抵触しない。 ToolDefinitionをArc<Fn>で返す既存ファクトリ規約を踏襲し、SearchConfigを closure に move するだけのミニマルな受け渡し。manifest::MemoryConfigへの 2 フィールド追加はOption<usize>+ cascade で merge する既存パターンに従っている。- スコープ越境なし(llm-worker / pod / scope の責務境界に変更なし)。「memory crate は self-contained」という既存ポリシー (
lib.rs:1-7) もそのまま守られている。 - 派生 index を持たず都度スキャンとしている点も、原チケットの「FTS / vector は将来」とブレなし。
指摘事項
Blocking
なし。
Non-blocking / Follow-up(任意)
search.rs:115-122の summary 走査がhit_limit上限ガードを通っていない。現状はlimit - hits.len()をscan_fileに渡しているのでlimit == 0でも 0 が伝わって動作上は問題ないが、可読性として decisions / requests と同じif hits.len() < limitガードを前置きしておく方が一貫し、将来の修正で誤ってusizeunderflow を踏み込む隙を消せる。SearchConfig適用ロジックが controller 側に展開コードとして書かれている (controller.rs:249-255)。MemoryConfig→SearchConfigの変換をFromimpl で memory crate 側に持たせるとテストしやすく、controller を細くできる。manifest を memory に依存させたくない場合は逆向き (manifest側にto_search_config) でも可。今のままでも動くので任意。- frontmatter の YAML パース失敗時、
kindfilter 指定があるとそのファイルが完全に excluded になる (search.rs:189-198)。仕様上「frontmatter parse 失敗時は本文 grep 継続」と書かれているので、kind filter 指定時のみ skip するのは spec 通り(filter で絞り込みたいユーザーが unknown-kind のファイルを取りたいケースは無い)。ただしドキュコメントに「kind filter ありで frontmatter 壊れているファイルは skip」と一行足しておくと混乱しない。 KnowledgeSearchToolは frontmatter parse 失敗ファイルも逐次 lower-case 比較するため負荷がやや高い。本チケットの「都度スキャン」「FTS は将来」前提なので問題視はしないが、hit_limitを 0 や巨大値にしたユーザーに対して description などに足切り入れる余地は将来検討。
Nits
MEMORY_SEARCH_DESCRIPTION/KNOWLEDGE_SEARCH_DESCRIPTIONがhit_limitに言及しているが、tool input にはこのフィールドが無い(manifest 側 tunable)。LLM がhit_limitを引数に入れたくならないか軽く心配。「(configurable via manifest)」のような括弧書きで明示してもよい。parse_hitsテストヘルパーがOwnedMemoryHit/OwnedKnowledgeHitで「Owned」プレフィックスを持つが、テスト内のシリアライズ用 struct を「Owned」と呼ぶ意図が明示されていない。parsed_*などでも可。
判断
Approve(完了可) — 原チケットの要件と完了条件はすべて実装に対応付けが取れており、補正(Read/Write/Edit signature 切り替え・出力スキーマ差別化・slug 完全一致を Read 側へ移譲)はチケット本文にも明確に反映されている。コードベースの既存パターンを踏襲しており、歪みも gold-plating も無し。指摘は全て任意の follow-up。