use crate::memory::{self, Memory}; use std::fmt::Write; /// Build context preamble by searching memory for relevant entries. /// Entries with a hybrid score below `min_relevance_score` are dropped to /// prevent unrelated memories from bleeding into the conversation. pub(super) async fn build_context( mem: &dyn Memory, user_msg: &str, min_relevance_score: f64, session_id: Option<&str>, ) -> String { let mut context = String::new(); // Pull relevant memories for this message if let Ok(entries) = mem.recall(user_msg, 5, session_id).await { let relevant: Vec<_> = entries .iter() .filter(|e| match e.score { Some(score) => score >= min_relevance_score, None => true, }) .collect(); if !relevant.is_empty() { context.push_str("[Memory context]\n"); for entry in &relevant { if memory::is_assistant_autosave_key(&entry.key) { continue; } let _ = writeln!(context, "- {}: {}", entry.key, entry.content); } if context == "[Memory context]\n" { context.clear(); } else { context.push('\n'); } } } context } /// Build hardware datasheet context from RAG when peripherals are enabled. /// Includes pin-alias lookup (e.g. "red_led" → 13) when query matches, plus retrieved chunks. pub(super) fn build_hardware_context( rag: &crate::rag::HardwareRag, user_msg: &str, boards: &[String], chunk_limit: usize, ) -> String { if rag.is_empty() || boards.is_empty() { return String::new(); } let mut context = String::new(); // Pin aliases: when user says "red led", inject "red_led: 13" for matching boards let pin_ctx = rag.pin_alias_context(user_msg, boards); if !pin_ctx.is_empty() { context.push_str(&pin_ctx); } let chunks = rag.retrieve(user_msg, boards, chunk_limit); if chunks.is_empty() && pin_ctx.is_empty() { return String::new(); } if !chunks.is_empty() { context.push_str("[Hardware documentation]\n"); } for chunk in chunks { let board_tag = chunk.board.as_deref().unwrap_or("generic"); let _ = writeln!( context, "--- {} ({}) ---\n{}\n", chunk.source, board_tag, chunk.content ); } context.push('\n'); context }