use crate::memory::{self, MemoryResult};
use std::sync::atomic::{AtomicBool, Ordering};
const MAX_SNIPPETS: usize = 2;
pub(crate) const SNIPPET_CHARS: usize = 500;
pub(crate) const MAX_HINT_CHARS: usize = 900;
const MIN_RANK: f64 = 0.1;
static STORE_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
pub async fn hints_for(query: &str) -> Option<String> {
if STORE_UNAVAILABLE.load(Ordering::Relaxed) {
return None;
}
let store = match memory::get_store() {
Ok(s) => s,
Err(_) => {
STORE_UNAVAILABLE.store(true, Ordering::Relaxed);
return None;
}
};
let results = match memory::search_brain(store, query, MAX_SNIPPETS * 3).await {
Ok(r) => r,
Err(_) => return None,
};
format_hints(&results)
}
pub(crate) fn format_hints(results: &[MemoryResult]) -> Option<String> {
let mut block = String::from("\n\n─── relevant brain notes ───\n");
let mut count = 0usize;
for r in results {
if count >= MAX_SNIPPETS {
break;
}
if r.rank < MIN_RANK {
continue;
}
let name = std::path::Path::new(&r.path)
.file_name()
.map(|n| n.to_string_lossy().to_string())
.unwrap_or_else(|| r.path.clone());
let snippet: String = r.snippet.chars().take(SNIPPET_CHARS).collect();
block.push_str(&format!("• **{name}**: {snippet}\n"));
count += 1;
}
if count == 0 {
return None;
}
if block.chars().count() > MAX_HINT_CHARS {
let mut capped: String = block.chars().take(MAX_HINT_CHARS).collect();
capped.push('…');
return Some(capped);
}
Some(block)
}