generate_stream previously did a non-streaming call and emitted the
whole response as one fake token. Now reqwest bytes_stream feeds a
line buffer; every token piece goes out as it arrives via the existing
Channel. SessionLogger's progressive display lights up unchanged.
Per-line parsers are pure fns with unit tests; unparseable lines are
skipped, server error lines bubble.
LlmConfig.provider ("ollama" | "openai", empty = sniff URL so legacy
configs keep working). Settings presets set it — a custom-port Ollama
no longer falls into the OpenAI branch and fails confusingly.
Also: test_connection now accepts an optional config override — the
wizard was passing one that Rust silently ignored, so it tested the
saved config instead of the URL the user just typed.
- chunk(): byte splits that landed mid multibyte char silently dropped
the whole chunk (accented/CJK lore). Back the boundary off to a char
boundary; regression test included.
- add_document(): DELETE the source first — re-adding a file no longer
doubles its chunks.
- chunks now record their embed_model (ALTER TABLE migration for old
DBs); search skips chunks from a different model; rag_list reports it;
new rag_reindex re-embeds everything, surfaced in the Lore panel as a
mismatch banner with a one-click Reindex.
set_llm_config only mutated an in-memory Mutex; lib.rs always started
from LlmConfig::default(). Config now round-trips through the same
dm-pal-prefs.json store as dataDir, with a defaults fallback so a
future shape change can't brick startup. Prefs consts now live in
lib.rs (pub) instead of being mirrored per-module.