feat(ai): few-shot exemplars + sticky Ollama preference

- Few-shot injection on /insights/generate/agentic: compresses prior
  training_messages into trajectory blocks (tool calls + result summaries)
  and injects into the system prompt. Hardcoded default ids with optional
  request override.
- New fewshot_source_ids column on photo_insights (+ migration) to track
  which exemplars influenced a given row, for downstream training-set
  filtering. Chat amend rows stamp None with a lineage note.
- Ollama client now remembers which server (primary/fallback) most
  recently succeeded and tries it first on the next call, via a shared
  Arc<AtomicBool>. Avoids re-404ing the primary on every agent iteration
  when the chosen model only lives on the fallback.
- Demote noisy logs: daily_summary "Summary match" lines to debug;
  inner chat_with_tools non-2xx body log from error to warn (outer
  layer owns the terminal-error signal).
- Drift-guard tests for summarize_tool_result covering the success /
  empty / error / unknown shape for every tool.
- Tidy: three pre-existing clippy warnings cleaned up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cameron
2026-04-24 13:54:06 -04:00
parent 29f32b9d22
commit f0ae9f95dc
12 changed files with 639 additions and 82 deletions

View File

@@ -268,7 +268,7 @@ impl DailySummaryDao for SqliteDailySummaryDao {
.into_iter()
.take(limit)
.map(|(similarity, summary)| {
log::info!(
log::debug!(
"Summary match: similarity={:.3}, date={}, contact={}, summary=\"{}\"",
similarity,
summary.date,
@@ -388,7 +388,7 @@ impl DailySummaryDao for SqliteDailySummaryDao {
.into_iter()
.take(limit)
.map(|(combined, similarity, days, summary)| {
log::info!(
log::debug!(
"Summary match: combined={:.3} (sim={:.3}, days={}), date={}, contact={}, summary=\"{}\"",
combined,
similarity,