feat(memory): embedders vectoriels réels HTTP + ONNX derrière features (LOT C1)

Remplace les StubEmbedder pour les stratégies localServer/api/localOnnx par de
vrais moteurs, chacun derrière une feature cargo off-by-default — la posture
fondatrice « rien d'imposé, zéro dépendance » (défaut none → rappel naïf) reste
byte-for-byte inchangée.

C1a (feature vector-http, reqwest rustls optional):
- HttpEmbedder couvrant localServer (Ollama/llama.cpp) et api (OpenAI/Voyage…),
  payload OpenAI-compatible /v1/embeddings, ordre restauré par index, bearer
  token lu via env var (jamais en clair), timeout client 30s.
- detect_ollama() pour la détection de l'existant (C3).

C1b (feature vector-onnx, fastembed v5 optional):
- OnnxEmbedder en-process (e5-small, dim 384), init paresseuse + spawn_blocking,
  cache modèle sous <app_data>/embedders/onnx — aucun download au build ni au
  first-run, uniquement à la demande au 1er embed.
- Catalogue RECOMMENDED_ONNX_MODELS + ONNX_CACHE_SUBDIR + onnx_model_is_cached
  exposés (sans feature) pour la config (C2) et la popup (C3).

embedder_from_profile(profile, onnx_cache_dir) dispatche feature-gated ; sans la
feature, retombe sur StubEmbedder (Unsupported) → fallback naïf via
AdaptiveMemoryRecall. Composition root (build_memory_recall) propage le cache dir.

Tests: 10 HTTP + 6 ONNX (dont 2 #[ignore] download réel) + 26 vectoriels, verts
en défaut, --features vector-http et --features vector-onnx.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 19:00:40 +02:00
parent b39c11a64d
commit 32398827fb
10 changed files with 2012 additions and 50 deletions

View File

@ -23,3 +23,20 @@ git2 = { workspace = true }
# Filesystem change notifications used to *wake* the orchestrator poll loop early
# (the poll loop remains the robust cross-platform correctness guarantee).
notify = "6"
# Optional HTTP client for the real `localServer`/`api` embedders (LOT C1a,
# §14.5.3). `default-features = false` + `rustls-tls` keeps it OpenSSL-free so the
# AppImage stays portable; pulled in *only* under the `vector-http` feature so the
# zero-dependency default (`none` strategy) compiles nothing extra.
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"], optional = true }
# Optional in-process ONNX embedder (LOT C1b, §14.5.3). rustls all the way down
# (HF model download + ort binaries fetched at build time, NOT load-dynamic) so the
# AppImage stays self-contained and OpenSSL-free. Pulled in *only* under the
# `vector-onnx` feature; the zero-dependency default compiles nothing extra.
fastembed = { version = "5", default-features = false, features = ["hf-hub-rustls-tls", "ort-download-binaries-rustls-tls"], optional = true }
[features]
# Real HTTP-backed embedders (`localServer` Ollama/llama.cpp, `api` OpenAI/Voyage…).
# OFF by default: the founding posture is `none` ⇒ naïve recall, zero dependency.
vector-http = ["dep:reqwest"]
# Real in-process ONNX embedder (`localOnnx`). OFF by default, same posture.
vector-onnx = ["dep:fastembed"]