use std::path::Path;
use crate::bm25;
use crate::hybrid;
use crate::{HDF5Memory, MemoryError, Result, SearchResult};
impl HDF5Memory {
pub fn hybrid_search(
&mut self,
query_embedding: &[f32],
query_text: &str,
vector_weight: f32,
keyword_weight: f32,
k: usize,
) -> Vec<SearchResult> {
let bm25 = bm25::BM25Index::build(&self.cache.chunks, &self.cache.tombstones);
let scored = hybrid::hybrid_search(
query_embedding,
query_text,
&self.cache.embeddings,
&self.cache.chunks,
&self.cache.tombstones,
&bm25,
vector_weight,
keyword_weight,
k,
);
let mut results: Vec<SearchResult> = scored
.into_iter()
.map(|(idx, score)| {
let w = self.cache.activation_weights[idx];
SearchResult {
score: score * w.sqrt(),
chunk: self.cache.chunks[idx].clone(),
index: idx,
timestamp: self.cache.timestamps[idx],
source_channel: self.cache.source_channels[idx].clone(),
activation: w,
}
})
.collect();
results.sort_by(|a, b| b.score.partial_cmp(&a.score).unwrap_or(std::cmp::Ordering::Equal));
let hit_indices: Vec<usize> = results.iter().map(|r| r.index).collect();
self.apply_hebbian_boost(&hit_indices);
self.flush().ok();
results
}
fn apply_hebbian_boost(&mut self, hit_indices: &[usize]) {
for &idx in hit_indices {
self.cache.activation_weights[idx] += self.config.hebbian_boost;
}
}
pub fn get_chunk(&self, index: usize) -> Option<&str> {
if index < self.cache.chunks.len() && self.cache.tombstones[index] == 0 {
Some(&self.cache.chunks[index])
} else {
None
}
}
pub fn generate_agents_md(&self) -> String {
crate::agents_md::generate(&self.config, &self.cache, &self.sessions, &self.knowledge)
}
pub fn write_agents_md(&self) -> Result<()> {
let md = self.generate_agents_md();
let md_path = self.config.path.with_extension("agents.md");
std::fs::write(&md_path, md).map_err(MemoryError::Io)
}
pub fn read_agents_md(path: &Path) -> Result<String> {
let md_path = path.with_extension("agents.md");
std::fs::read_to_string(&md_path).map_err(MemoryError::Io)
}
}