6.9 KiB
6.9 KiB
Review: LLM プロバイダ/モデルカタログ
前提・要件の確認
要件 1: TOML 形式の定義([[provider]] 配列、auth_hint = { kind, env? })
満たされている。
crates/provider/assets/providers.tomlの 4 エントリがチケット例(tickets/llm-provider-catalog.md:15-46)と一字一句合致している(id / display_name / scheme / base_url / auth_hint.kind / env 名 / default_models の順序と値)。AuthHint側は#[serde(tag = "kind", rename_all = "snake_case")]でインラインテーブル{ kind = "api_key", env = "..." }を受け付ける(crates/provider/src/catalog.rs:44-56)。kind = "codex_oauth"はデフォルトのsnake_case変換がcodex_o_authになってしまう問題を#[serde(rename = "codex_oauth")]で明示的に回避しており、既存AuthRef::CodexOAuth(crates/manifest/src/model.rs:70)と同じ書き方になっている。整合している。
要件 2: Vec<ProviderEntry> を返す読取 API を crates/provider に 1 本公開
満たされている。
pub fn load() -> Result<Vec<ProviderEntry>, CatalogError>が主 API(catalog.rs:108)。補助としてload_builtin/load_from_pathも公開されており、後者はテストと将来の明示パス指定に合理的。- 配置は
crates/provider直下(lib.rs:14でpub mod catalog;)。llm-workerに下りていない。Memory の「llm-worker は低レベル基盤に留める」方針に整合。
要件 3: 配置パス(builtin の include_str! / user override 置換 / 両方読めなければ builtin)
満たされている。
BUILTIN_CATALOG: &str = include_str!("../assets/providers.toml")(catalog.rs:18)。- user override は
$XDG_CONFIG_HOME/insomnia/providers.toml、未設定時は$HOME/.config/insomnia/providers.toml(catalog.rs:137-154)。チケットでは$HOMEフォールバックは明示されていないが、XDG Base Directory spec の既定挙動として妥当で、過剰とも言えない。 - マージではなく置換(
catalog.rs:108-115)。load_prefers_override_over_builtin/load_falls_back_to_builtin_when_override_absentテストで両経路をカバー。
要件 4: ProviderEntry + model_id → ModelConfig の変換
満たされている。
ProviderEntry::to_model_config(&self, model_id: impl Into<String>) -> ModelConfig(catalog.rs:82-99)がAuthHintの 3 バリアントをAuthRefに 1:1 で写す。capabilityは常にNoneで返し、build_client側の 3 段階 fallback(ModelConfig.capability→capability::lookup→scheme default、lib.rs:120-124)に委ねるのはチケット設計判断「capability宣言をカタログに入れない」(llm-provider-catalog.md:77-79)と整合。to_model_config_maps_auth_hintテスト(catalog.rs:208-229)で 3 バリアント全部を確認。
要件 5: 完了時の動作(builtin 取得 / override 置換 / UI 未実装段階で unit test e2e)
満たされている。
ollama_entry_builds_client(catalog.rs:231-239)が「カタログ読取 →ProviderEntry選択 →ModelConfig生成 →build_clientが成功」の経路を端から端まで通している。Ollama はAuthRef::Noneなので環境変数依存がなく、常に成功する選択として適切。cargo test -p providerが 43 件全部 pass、ワークスペースcargo buildもクリーン。
アーキテクチャ・スコープ
- レイヤ分離:
crates/provider内に閉じ、llm-workerには漏れていない。build_client/resolve_authの既存シグネチャは一切変更していない(lib.rs:53-146は今回の差分外)。非破壊性 OK。 - 責務分離:
AuthHint(UI メタ)とAuthRef(ランタイム解決)を別型として定義し、to_model_configで 1:1 変換する設計は、チケット「設計判断:auth_hintとAuthRefの二重定義」(llm-provider-catalog.md:73-75)の意図を正確に反映している。型を流用する代替案もあり得たが、UI ヒントにfile: Option<PathBuf>が紛れ込むとカタログのスコープが広がるため、別型にしたのは妥当。 - 過剰抽象の有無:
discover: Option<DiscoverMode>のような先取り実装はされていない(コメントで言及のみ、catalog.rs:60-61)。チケットの「auto_discover は別チケット」方針に従っている。 - 依存追加:
tomlを dev-dependencies から regular dependencies に「移動」する形でcargo add相当の編集がされている。手動編集ではあるが、既存行を move しただけなので Memory のUse cargo add方針からの逸脱は軽微。 - モジュール分割:
pod.rs等の既存 primary ファイルに詰め込まず、catalog.rsとして独立モジュール化している。Memory の「feature モジュール分割」方針に合致。 - Scope 外の侵食: UI / auto_discover / 編集 UI / プロファイルのどれにも触れていない。境界遵守。
指摘事項
Non-blocking / Follow-up
$HOMEフォールバック(catalog.rs:143-152)がチケット本文に明示されていない。妥当な挙動ではあるが、チケットの「配置パス」記述と実装の解像度に乖離があり、ユーザーが後から読んだとき驚きがある。ticket 側に一行追記するか、コード側のドキュメント(モジュール冒頭 doc)に「XDG 既定挙動として$HOME/.config/...にフォールバック」を明記しておくと親切。
Nits
-
catalog.rs:106の doc コメントに "sigh" というタイポがある("silent" の意図と思われる)。該当箇所:/// 存在すれば builtin を置き換える。存在しなければ builtin のみ。 /// user override が存在するが壊れている場合はエラーを返す(silent /// fallback はしない — ユーザーが書いた設定が sigh なく無視されて /// builtin に戻る挙動は気付きにくいため)。sigh→silentに直すか、日本語化で「気付かれず」等に差し替え。 -
builtin_ollama_shape(catalog.rs:173-183)の assert がscheme == Anthropicを確認しているが、コメントの「Ollama = Anthropic scheme」の意図はlib.rs:278-290のollama_succeeds_without_keyと重複する情報。コメントで相互参照しておくと将来の読み手に親切。
判断
Approve(完了可) — チケット要件 1〜5 は全て明確に満たされており、AuthHint/AuthRef の責務分離・レイヤ境界・既存 API 非破壊といったアーキテクチャ観点も適切。指摘は sigh タイポと $HOME フォールバックのドキュメント明示の 2 点のみで、どちらも blocking ではない。